I've been working on adding aspects to a Spring MVC webapp, and the aspects aren't executing. I've tried to boil it down to something dirt simple that clearly should work, but still no go. Here's where I'm at now:
// imports...
#Aspect
public class AuthCheckerAspect {
{
System.out.println("initting");
}
#Pointcut("execution(* * *(..))")
public void c() {}
#Before("c")
public void cc(JoinPoint pjp) throws Throwable {
System.out.println("test...");
}
}
As far as I can tell, the pointcut should apply to any method in any Spring-managed class (of which there are a lot in my application). I also added the following to my Spring config:
<aop:aspectj-autoproxy/>
I set a breakpoint at the System.out.println() statement in the cc() method, but it never caught (and yes, I'm positive that the debugger is attached; other breakpoints catch properly). I'm suspecting that the AuthCheckerAspect class is never getting loaded into the Spring context, because I also set a breakpoint within the initializer clause, and that never catches either; when I do the same with other Spring-managed classes, their breakpoints always catch during app startup.
Is there something else I need to be doing?
Thanks in advance.
Spring does not automatically mange #Aspects. Add <bean class="AuthCheckerAspect" /> to your context or annotate it with #Component and include in component scan path.
add this to your configuration file:
<context:annotation-config />
<context:component-scan base-package="root.package.to.be.scanned" />
<aop:aspectj-autoproxy>
<aop:include name="nameOfAspectBean" />
</aop:aspectj-autoproxy>
Related
I have just started to use Camel in one of my projects. I am trying to configure Camel with Spring, but having issues doing that.
I don't want to use xml configuration but rather go with Spring based Annotations for configuring Routes and Processors.
My App is a stand alone Spring Application, which will be run as Jar.
To keep the app running, I've a empty scheduled method which runs every x min.
Below are the dependencies in my build.gralde
// Spring //
compile('org.springframework:spring-core:5.0.0.RC2')
compile('org.springframework:spring-context:5.0.0.RC2')
compile('org.springframework:spring-beans:5.0.0.RC2')
compile('org.springframework:spring-context-support:5.0.0.RC2')
// Apache //
// Camel //
compile('org.apache.camel:camel-core:2.19.1')
compile('org.apache.camel:camel-spring:2.19.1')
snapshot of beans.xml
<context:annotation-config/>
<tx:annotation-driven/>
<context:component-scan base-package="my.package" />
<camelContext id="aggregatorCamelContext" autoStartup="true" xmlns="http://camel.apache.org/schema/spring">
<package>
my.package.camel
</package>
</camelContext>
Sample RouteBuilder
#Component
public class SampleRoute extends RouteBuilder {
#Autowired
MyClass myObject;
#Override
public void configure() throws Exception {
from("file:filelist")
.process(myObject)
.to("file:processedList");
}
}
To keep the app alive ( I know bit hacky, but suffices for now )
#Component
#EnableScheduling
public class KeepitAlive {
#Scheduled(fixedRate = 1000l)
public void run(){
System.out.println("KeepitAlive.run "+ Thread.currentThread().getName() );
}
}
Main Class. I have tried both the methods, Initializing Spring context as well as Camel Main, but to no luck
public class MyApplication {
public static void main(String[] args) throws Exception {
/*AbstractXmlApplicationContext context =
new ClassPathXmlApplicationContext("path/to/beans.xml");*/
Main main = new Main();
main.setApplicationContextUri("path/to/beans.xml");
main.start();
}
}
If I put my Route within camelContext declaration itself, it works absolutely fine,
<route>
<from uri="file:filelist"/>
<to uri="file:processedlist"/>
</route>
I've also looked into Camel Spring Integration documentation, but it also contains xml based configuration.
Could anybody please guide me in right direction.
You are using Camel's own package scanning via
<package>
my.package.camel
</package>
You should use <contextScan> if you want Camel to find the Spring #Component Camel routes.
See the Camel spring documentation for more: http://camel.apache.org/spring.html
Figured it out ultimately. Need to extend SpringRouteBuilder instead of RouteBuiler above in SampleRoute class.
Anybody struggling with issues, I suggest once go through Camel in Action book.
Somehow I missed it in the beginning which costed me lot of time figuring out trivial things that this book covers.
i really hope someone can help me, i am trying to create some very simple AOP Operations in my web-application.
Unfortunately it is not triggered at all.
Here my configs:
web.xml (to load application.xml)
<!-- web.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application*.xml</param-value>
</context-param>
And the application.xml
<!--application.xml-->
<aop:aspectj-autoproxy proxy-target-class="true" /> <!-- i tried with and without proxy-->
<bean id="config" class="com.whatever.config.Configuration"/> <!-- beans are not definend in application.xml, but in a separate class-->
The config class
#Configuration
#PropertySource({ "classpath:/ui.properties" })
#Import({ somclass.class, ScanBean.class})
public class Configuration {
}
The scanbean class
#Configuration
#ComponentScan(basePackages = { "com.ui.common", "com.ui.aspects" })
public class ScanBean {
#Bean
public DefaultEntityServiceAspect defaultEntityServiceAspect() {
return new DefaultEntityServiceAspect();
}
}
Beans are there and everything starts without any error.
The aspect beans...
The annotation
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultEntity {}
// the aspect itself
#Aspect
public class DefaultEntityServiceAspect {
private final Logger logger = Logger.getLogger(DefaultEntityServiceAspect.class);
#Around("#annotation(com.ui.aspects.DefaultEntity)")
public void setDefaultEntityFields(ProceedingJoinPoint joinPoint) throws Throwable {
logger.warn("doing something 2 huhu");
joinPoint.proceed();
}
}
And finally the bean itself
#Service
#Scope("session")
public class AdminBean implements Serializable {
// some code...
#DefaultEntity
public void wtfIsWrongWithYou() {
logger.debug("am i working?");
}
}
If i write a simple JUNIT Test, it is working like expected. As soon as i deployed it to the server (tomcat). Nothing works anymore.
I found a 1000 tips, but non of them was working. I think i read everything here on stackoverflow :) but a solution was not found. I would really appreciate every tip.
Cheers!
Edit:
I created a small project on github. I still did not get it run .. if someone has a hint, please let me know! Thank you!
I finally made it work in my "big" application as well. The root cause was that i externalized all the spring / hibernate aso. libraries.
In fact i was using the shared lib settings from tomcat and had all my spring libraries on that server. This is working fine as long as you do not use aspectj / spring aop.
After i created a war file with the libs included (WEB-INF/lib) it was working immediately.
It also kind of makes sense, since the libs are loaded by different classloaders aso... hope it helps somebody as well!
Has anyone tried to auto-wire different beans into a Spring-managed bean based on a condition? For e.g. if some condition is met, inject class A, else B? I saw in one of the Google search results that it is possible with SpEL (Spring Expression Language), but could not locate a working example.
There are multiple ways to achieve this. Mostly this depends on the conditioning you want to perform.
Factory bean
You can implement simple factory bean to do the conditional wiring. Such factory bean can contain complex conditioning logic:
public MyBeanFactoryBean implements FactoryBean<MyBean> {
// Using app context instead of bean references so that the unused
// dependency can be left uninitialized if it is lazily initialized
#Autowired
private ApplicationContext applicationContext;
public MyBean getObject() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(applicationContext.getBean(DependencyX.class));
} else {
myBean.setDependency(applicationContext.getBean(DependencyY.class));
}
return myBean;
}
// Implementation of isSingleton => false and getObjectType
}
Maybe a bit better approach is if you use factory bean to create the dependency bean in case you want to have only one such bean in your application context:
public MyDependencyFactoryBean implements FactoryBean<MyDependency> {
public MyDependency getObject() {
if (true /* some condition */) {
return new MyDependencyX();
} else {
return new MyDependencyY();
}
}
// Implementation of isSingleton => false and getObjectType
}
SpEL
With SpEL there are many possibilities. Most common are system property based conditions:
<bean class="com.example.MyBean">
<property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" />
</bean>
Property placeholder
You can have property placeholder resolve your bean reference. The dependency name can be part of the application configuration.
<bean class="com.example.MyBean">
<property name="dependency" ref="${dependencyName}" />
</bean>
Spring profiles
Usually the condition you want to evaluate means that a whole set of beans should or should not be registered. Spring profiles can be used for this:
<!-- Default dependency which is referred by myBean -->
<bean id="dependency" class="com.example.DependencyX" />
<beans profile="myProfile">
<!-- Override `dependency` definition if myProfile is active -->
<bean id="dependency" class="com.example.DependencyY" />
</beans>
Other methods can mark the bean definition as lazy-init="true", but the definition will be still registered inside application context (and making your life harder when using unqualified autowiring). You can also use profiles with #Component based beans via #Profile annotation.
Check ApplicationContextInitialier (or this example) to see how you can activate profiles programatically (i.e. based on your condition).
Java config
This is why Java based config is being so popular as you can do:
#Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(dependencyX());
} else {
myBean.setDependency(dependencyY());
}
return myBean;
}
Of course you can use more or less all configuration methods in the java based config as well (via #Profile, #Value or #Qualifier + #Autowired).
Post processor
Spring offers numerous hook points and SPIs, where you can participate in the application context life-cycle. This section requires a bit more knowledge of Spring's inner workings.
BeanFactoryPostProcessors can read and alter bean definitions (e.g. property placeholder ${} resolution is implemented this way).
BeanPostProcessors can process bean instances. It is possible to check freshly created bean and play with it (e.g. #Scheduled annotation processing is implemented this way).
MergedBeanDefinitionPostProcessor is extension of bean post processor and can alter the bean definition just before it is being instantiated (#Autowired annotation processing is implemented this way).
UPDATE Oct 2015
Spring 4 has added a new method how to do conditional bean registration via #Conditional annotation. That is worth checking as well.
Of course there are numerous other ways with Spring Boot alone via its #ConditionalOn*.
Also note that both #Import and #ComponentScan (and their XML counterparts) undergo property resolution (i.e. you can use ${}).
I had a case where I needed to inject different beans depending on property: "my.property". In my case this solution was successful:
<property name="name" ref="#{ ${my.property:false}==true ? 'bean1' : 'bean2' }"/>
I needed to add the apostrophes around bean names in order to make it work.
In your #Configuration class declare a bean to be conditionally created:
#Bean
#Conditional(CustomFeatureCondition.class)
public Stuff stuff() {
return new Stuff ();
}
In the place of using just #Autowire it with required = false option:
#Component
#Setter(onMethod_ = #Autowired(required = false))
public class AnotherStuff {
private Stuff stuff;
// do stuff here
}
This way you'll get Stuff bean if it exists in the context and stuff = null if it doesn't.
I suppose the simpest way:
#Autowired #Lazy
protected A a;
#Autowired #Lazy
protected B b;
void do(){
if(...) { // any condition
// use a
} else {
// use b
}
}
In case you do not declare nessassary bean, Spring throws at runtime NoSuchBeanDefinitionException
Trying to design simple aspect,that will print word "logg" to console,when any of public methods executed.
aspect:
#Aspect
public class LoggingAspect {
#Pointcut("execution(public * *(..))")
public void publicServices() {
};
#Before("publicServices()")
public void logg() {
System.out.println("logg");
}
}
xml config:
<context:component-scan base-package="aspectlogging" />
<aop:aspectj-autoproxy/>
<bean id="loggingAspectHolder" class="aspectlogging.LoggingAspect"/>
simple bean:
package aspectlogging;
#Component
public class TestableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
test:
public class TestLogging {
public static void main(String[] args) {
TestableBean tb = new TestableBean();
tb.setName("yes");
tb.getName();
}
}
I expect,that result of running of TestLogging will be "logg" word in console,and no output returned.
Do I understand AOP correctly in this case?
With #Around advice, you need to have a ProceedingJoinPoint pjp argument to the advising method and to call pjp.proceed() at the point in the advisor when you want the wrapped method to be called. It's easier to use #Before advice really, when what you've done will otherwise work just fine.
[EDIT]: Also, you must let Spring construct your beans for you instead of directly calling new. This is because the bean object is actually a proxy for your real object (which sits inside it). Because your target object doesn't implement an interface, you will need to have the cglib library on your classpath in addition to the Spring libraries. (Alternatively, you can go with using AspectJ fully, but that requires using a different compiler configuration.)
To create your beans, you first need to create a Spring context and then query that for the bean instance. This means you change from:
TestableBean tb = new TestableBean();
To (assuming you're using Spring 3, and that your XML config is in "config.xml" somewhere on your classpath):
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
TestableBean tb = context.getBean(TestableBean.class);
The rest of your code remains the same (after adjusting for import statements and possibly additional dependencies).
Not quite sure on this one, but maybe you need to use a spring managed TestableBean to have spring AOP pick up the method call.
edit: of course, you can't use #Around the way that you provided - but this subject has been addressed by another answer, so it's omitted here.
edit2: If you need help on how to get a spring managed bean, please feel free to ask. but since you already got your aspect bean set up, I believe you can handle this :)
edit3: Hehe. Ok.. maybe not :)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
will load your application context.
Load beans from there by calling:
TestableBean testableBean = (TestableBean )ctx.getBean("testableBean ");
Define the TestableBean just like you did with your Aspect bean.
edit4: Now I'm pretty sure that the fault is the non-spring managed bean.
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, then Spring AOP is the right choice. If you need to advise domain objects, or any other object not managed by the Spring container, then you will need to use AspectJ.
Taken from: http://static.springsource.org/spring/docs/2.0.x/reference/aop.html
This is my 1st time trying Spring3's #Scheduled , but found I cannot commit to DB. This is my code :
#Service
public class ServiceImpl implements Service , Serializable
{
#Inject
private Dao dao;
#Override
#Scheduled(cron="0 0 * * * ?")
#Transactional(rollbackFor=Exception.class)
public void hourly()
{
// get xxx from dao , modify it
dao.update(xxx);
}
}
I think it should work , I can see it starts-up hourly and load xxx from DB , but data is not committed to DB.
There's been tx:annotation-driven in spring's xml :
<bean id="entityManagerFactoryApp" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myapp"/>
</bean>
<bean id="transactionManagerApp" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryApp" />
</bean>
<tx:annotation-driven transaction-manager="transactionManagerApp" />
Can somebody tell me what I missed here ?
I have one 'dirty' solution :
#Service
public class ServiceImpl implements Service , Serializable
{
#Inject
private Dao dao;
#Inject
#Qualifier("transactionManagerApp")
private PlatformTransactionManager txMgrApp;
#Override
#Scheduled(cron="0 0 * * * ?")
#Transactional(rollbackFor=Exception.class)
public void hourly()
{
final TransactionTemplate txTemplateApp = new TransactionTemplate(txMgrApp);
txTemplateApp.execute(new TransactionCallbackWithoutResult()
{
#Override
protected void doInTransactionWithoutResult(TransactionStatus status)
{
//get xxx from dao
dao.update(xxx);
}
});
}
}
It works fine here , but it is so redundant , making the code harder to read.
I wonder why TransactionManager is not injected (and opened) in the previous code snippets?
Thanks a lot !
You probably have figured this out or moved on (I hope so), but for the benefit of others:
The #Transactional annotation tells Spring to wrap your original ServiceImpl bean with a dynamic proxy that also implements 'Service' (by default Spring proxies the interface, not the implementation). This proxy will transparently handle the creation and commit/rollback of the transaction when you call hourly() on the proxy. However, if you call hourly() directly on your implementation (which is what is happening above), the proxy is bypassed, so there is no transaction.
http://blog.springsource.org/2012/05/23/understanding-proxy-usage-in-spring/
The solution is to either
Demarcate the transaction programmatically as you are doing in your 'dirty' solution (you don't need the annotations is this case).
Make sure that your #Scheduled method makes its call to dao.update(xxx); via the Service interface, not directly on your implementation (thereby going through the proxy). Basically you need to move the #Scheduled method to another bean.
I hope that is clear enough!
When you use annotation-driven support, it only works on classes created within that context. My bet is that ServiceImpl is not created in the same context as your transaction manager (either directly or by annotation scanning).
I had the same problem and after spending time on it, I realized that I got an exception after the dao.update() call in some unrelated code that didn't check null value - so it simply broke the transaction.
There was no stackTrace printing because it has been treated well by spring (some catch block).
I spent a while on that.
So - just verify that your transaction method completes till its end.
Hope it will help someone.
Yosi Lev