in this moment i am facing one problem and really dont know what i am doing wrong. I am coding logging for my webservice using Spring framework and AOP in #AspectJ style. I got two bundles - background and frontend. In background bundle I have LogAspect, which look like this:
#Aspect
public class LogAspect {
#Pointcut("#annotation(logMethod)")
public void logMethodAnnotated(LogMethod logMethod){}
#Before("logMethodAnnotated(logMethod)")
public void beforeLogMethodAnnotated(JoinPoint jp){
//actions
}
#After("logMethodAnnotated(logMethod)")
public void afterLogMethodAnnotated(JoinPoint jp){
//actions
}
}
and META-INF/spring/background-osgi.xml:
<context:annotation-config />
<context:component-scan base-package="simon.background"/>
<context:load-time-weaver />
and also META-INF/aop.xml:
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="simon.background.*"/>
<include within="simon.frontend.controller.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="simon.background.log.LogAspect"/>
</aspects>
</aspectj>
In frontend bundle I've just put into aplicationContext.xml <context:load-time-weaver aspectj-weaving="on" />. But the code is acting very strange. I found out, that there is some problem, when I put into my advice methods JoinPoint as argument. (I mean, when I got advice methods without arguments, so there were no JoinPoin in method header, everything has been working fine and advices has been running before and after #LogMethod (my annotation, which I use to say, that i want to log this method) annotated methods). But now it is working like this:
- when I start server and so that the bundles are deployed for the first time, then the advices are run just for methods, they are #LogMethod annotated and belongs to background bundle, but not for annotated methods in frontend.controller.
- and in addition, when I have done some changes in one of my controllers, saved it and deployed just frontend bundle, then when I run #LogMethod annotated method, I got this error:
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.LinkageError: loader constraint violation: when resolving method "simon.background.log.LogAspect.afterLogMethodAnnotated(Lorg/aspectj/lang/JoinPoint;)V" the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) of the current class, simon/frontend/controller/HuhController, and the class loader (instance of com/springsource/kernel/userregion/internal/equinox/KernelBundleClassLoader) for resolved class, simon/background/log/LogAspect, have different Class objects for the type /aspectj/lang/JoinPoint;)V used in the signature
Any ideas what is going on and how can i fix it, so my program will be able to run advices correctly?
One additional note, it could maybe help: When I run this in Debug mode with advices without JoinPoint argument, I realized, that both advices were running twice for one method.
On running twice, could it be because you are using both and
at the same time? Difference between <context:annotation-config> vs <context:component-scan>
Your pointcut has been triggered twice because your expression only constraints annotation type. When a method is called, call() and execution() are both match this expression so.
You can use #annotation(xxx) && execution(* *(..)) on your point cut to restrict the condition on execution only.
Related
This is what I've tried so far and my interceptor is not triggered (no "TATATA" in my logs) :
My interceptor AopLoggingInterceptor.java :
package fr.mycompany.bus.flow.reco.ani.custom.interceptor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AopLoggingInterceptor {
#Around("execution(* org.mule.api.transport.MessageReceiver.routeMessage(org.mule.api.MuleMessage))")
public Object addMonitor(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("TATATA Before");
Object object = pjp.proceed();
System.out.println("TATATA After");
return object;
}
}
META-INF/aop.xml :
<aspectj>
<aspects>
<aspect name="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</aspects>
<weaver options="-verbose">
<!-- Weave types that are within the org.mule.* packages. -->
<include within="org.mule.*" />
</weaver>
</aspectj>
My Mule/Spring config file :
<?xml version="1.0" encoding="UTF-8"?>
<mule >
<spring:beans>
<context:component-scan base-package="fr.mycompany.bus" />
<context:annotation-config />
<aop:aspectj-autoproxy />
<!-- Aspect -->
<spring:bean name="aopLoggingInterceptor" class="fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor" />
</spring:beans>
</mule>
My Mule file config consists of one flow with one inbound endpoint, 2 outbound endpoints, loggers and transformers (valid flow widely tested).
VM args :
-XX:PermSize=128M -XX:MaxPermSize=256M -javaagent:D:\path\to\mule\opt\aspectjweaver-1.6.11.jar
Extract from mule file starting in Eclipse which shows weaving is created :
[MuleApplicationClassLoader#2934847] info AspectJ Weaver Version 1.6.11 built on Tuesday Mar 15, 2011 at 15:31:04 GMT
[MuleApplicationClassLoader#2934847] info register classloader org.mule.module.launcher.MuleApplicationClassLoader#2934847
[MuleApplicationClassLoader#2934847] info using configuration /D:/BusToolBox/workspaces/dev/.mule/apps/bus-esb-mrc-reco-ani/classes/META-INF/aop.xml
[MuleApplicationClassLoader#2934847] info register aspect fr.mycompany.bus.flow.reco.ani.custom.interceptor.AopLoggingInterceptor
EDIT
It works nicely with a class included in my project, but not with mule classes :
[MuleApplicationClassLoader#6ad5934d] debug generating class 'fr.mycompany.bus.flow.reco.ani.custom.transformer.CustomerDetailToSiebelRecoAniOutputTransformer$AjcClosure1'
EDIT 2
Here is the best result I can get (by using <context:load-time-weaver />), the loading process tries to look for more classes loaded by difference classloaders is , but it results in :
ERROR 2014-08-08 16:00:46,802 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalStateException: ClassLoader [org.mule.module.launcher.MuleApplicationClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar
If I try to use spring-instrument-3.2.1.RELEASE.jar, I get same result as before (only main classloader is seen). Does it mean there is no hope with Mule ?
Have a look at this example for using Mule and Spring AOP. The example shows how to invoke Around advice for a component, but should be similar for the interceptor.
There is something very important when working with Spring AOP. In spring aop documentation is stated:
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 objects not
managed by the Spring container (such as domain objects typically),
then you will need to use AspectJ. You will also need to use AspectJ
if you wish to advise join points other than simple method executions
(for example, field get or set join points, and so on).
So if you want that your AopLoggingInterceptor is invoked for MessageReceiver method calls, that is not going to work because the MessageReceiver object is not managed by the Spring container. The Spring container doesn't "see" this objects.
In other words Spring-AOP cannot add an aspect to anything that is not created by the Spring factory. I found that statement here.
For example, now I want to intercept the method split() of java.lang.String by AOP.
Is it possible?
I have tried some normal methods but it did not work.
#Aspect
public class TestAspect {
#Before ("execution (* java.lang.String.split(..))")
public void logBeforeString(JoinPoint joinPoint) {
System.out.println("SPLIT BEGIN");
}
}
Below is the configuration file :
<!-- Aspect -->
<aop:aspectj-autoproxy />
<beans:bean id="TestAspect" class="com.dong.partner.aspect.TestAspect" />
With other pointcuts in my own project, they work well without problems.
So anyone knows how to intercept the imported external packages?
No, nothing in java.lang can be advised using execution. See this question for a more detailed explanation.
So anyone knows how to intercept the imported external packages?
You're using <aop:aspectj-autoproxy /> which means that Spring is using proxy based AOP. Essentially, Spring is creating a wrapper around each of your beans if the bean is advised with AOP. When a method on one of your beans is called, it hits the proxy/wrapper first. The proxy decides whether it should invoke your bean directly or whether one or more aspects should be called.
There are limits to the type of advice you can use with proxy based AOP. To intercept calls from your code to non-bean classes you need to switch to compile time or load time weaving with aspectj and use call pointcuts instead of execution pointcuts. The aspectj compiler will rejigger your bytecode so that any calls from your code to java.lang.String are rewritten to invoke the call pointcut.
Interestingly, this question had the opposite issue that you're experiencing.
I am new Spring AOP and Aspectj. I have seen various posts related to injected bean in an aspect being null and I have run into a similar problem. I am still not clear how I should proceed to get past the problem I am currently encountering.
Issue: Currently we are using Spring 3.2.3 and all injection is through Annotation. In my case, the dependent bean is injected properly by Spring but at the point of execution the injected bean is NULL. BTW, this doesn't happen all the time but what I can say is the stack trace when it fails and when it succeeds is slightly different. When the injected bean is not null (I can successfully use the injected bean service), the call to the before advice (in the aspect) always happens before the target method is called as it should.When the injected bean is NULL, the call to the aspect is from the first statement of the target method. At this point, I think another aspect is instantiated and has no reference to the injected bean. Here is the aspect I have created:
#Component
#Aspect
public class Enable{
private NameService nameService;
#Autowired
public void SetNameService(NameSerice service){
// service is injected properly
this.nameSerice = service;
}
#Before("* *.*(..)")
public void callBefore(JoinPoint jp){
//sometimes nameService is null and sometimes it not not
this.nameService.lookup(...);
}
}
Examining the various posts, one way to get around this (as suggested in the post) is to configure the aspect in the XML configuration file and use the factory-method ="aspectOf" and in the configuration inject the reference to the NameService bean as a property. Our whole project uses Annotation based injection (as stated earlier). Assuming I can still configure the above aspect in an XML configuration file, how can I get the reference NameService bean Id so that I can add it to the configuration. I also saw a post related to using Configurable annotation but I assume that is for objects created outside the Spring IOC.
Currently, the aspects are woven using Aspectj compile option in pom.xml. Our root-context.xml contains the entry context:annotation-config and the aspect is injected into Spring IOC because component-scan is turned on for the folder where the aspect resides. Any help will be appreciated
This is well common error when use aspects in spring, you should add
<context:spring-configured/>
and
<aop:aspectj-autoproxy />
also add
#Configurable
#Aspect
public class Enable
To your appContext.xml
aspectOf is another style to do the above but I prefer use the nature of context.
It might be too late to answer this question. But i have come across the same situation and i fixed it as below.
1) Have a setter and getter for "NameService" in your aspect class.
2) Mark "NameService" with #Component ("nameService")
3) Configure "nameService" in xml configuration using setter injection.
4) Re-Start your server after making changes.
This should resolve the problem of getting null for "NameService" in aspect.
I'm trying to change from load-time-weaving to compile-time-weaving with my Spring 2.5 app.
To do this, I did the following:
In my ant build file, I added
<path id="aspectPath">
<pathelement location="${lib.home}/spring-aspects.jar"/>
</path>
<taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
<classpath>
<pathelement location="${aspectj.home}/aspectjtools.jar"/>
</classpath>
</taskdef>
and replaced the reference to the javac compiler with the following
<iajc sourceroots="${src.home}"
destdir="${build.home}/WEB-INF/classes"
classpathRef="compile.classpath"
aspectPathRef="compile.classpath"
debug="${compile.debug}"
deprecation="${compile.deprecation}"
encoding="cp1252"
source="1.6"
target="1.6"
showWeaveInfo="${compile.debug}"/>
In applicationContext.xml I then replaced
<context:load-time-weaver/>
with
<context:spring-configured/>
Other configuration settings in my app context file, BTW, include
<tx:annotation-driven/>
<context:component-scan base-package="com.domain.somepackage"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
In the context.xml file, I removed the following from the loader tag
loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
When I run the build script, it compiles without errors.
I do get this warning however.
[iajc] warning at <Unknown>::0 Found #DeclareAnnotation while current release
does not support it (see 'org.aspectj.weaver.bcel.AtAjAttributes')
at the top, and this warning at the bottom:
[iajc] warning at C:\server-
lib\aspectjtools.jar!org\aspectj\ajdt\internal\compiler\
CompilerAdapter.class:121::0 advice defined in
org.aspectj.ajdt.internal.compiler.CompilerAdapter has not been
applied [Xlint:adviceDidNotMatch]
Most of the logging looks like:
[iajc] weaveinfo Join point 'method-execution(void com.kjconfigurator.upgra
de.Upgrade1_07HelperImp.addServiceParticipation(com.kjconfigurator.core.domain.U
ser, com.kjconfigurator.core.domain.ServiceAccount))' in Type 'com.kjconfigurato
r.upgrade.Upgrade1_07HelperImp' (Upgrade1_07HelperImp.java:196) advised by after
Returning advice from 'org.springframework.transaction.aspectj.AnnotationTransac
tionAspect' (spring-aspects.jar!AbstractTransactionAspect.class:77(from Abstract
TransactionAspect.aj))
I removed the tomcatspringweaver jar from the tomcat lib.
I am using aspectj1.7
When I start the app up, I get an error indicating that when a dao class is being injected into a service class there is an NPE at at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:104)
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested
PropertyAccessExceptions (1) are: PropertyAccessException 1:
org.springframework.beans.MethodInvocationException: Property 'dao' threw exception;
nested exception is java.lang.NullPointerException
The Dao class extends an AbstractJpaDao class that looks like this:
public abstract class AbstractJpaDao<T> {
private static Logger log = Logger.getLogger(AbstractJpaDao.class.getName());
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this. entityManager = entityManager;
}
...
}
It's been such a long time since all this was initially set up, I don't remember how all the configurations work. Nor do I understand class loaders or AspectJ very well. But something is not happening correctly, perhaps the Entitymanager is not being injected for some reason.
Questions.
What might be causing this?
Is <context:spring-configured/> really needed?
The package referenced by <context:component-scan base-package="com.domain.somepackage"/> does not include the Dao class in question. When I do add another component-scan tag with the dao's package in it, nothing different happens. Is this necessary?
Do you have any schedule tasks defined somewhere - it sounds like the scheduled tasks are getting triggered before the Spring context is completely initialized.
I finally found a solution to this problem with the help of a Spring consultant.
There was an aspect that was being called before it was fully initialized resulting in an NPE in the aspect. (Eclipse incorrectly showed the NPE originating in the class that was being advised.) I disabled the aspect by removing the annotations because the aspect was not critical; however, a better fix would have been for me to instruct Spring to initialize that class ahead of the others, or use a point cut expression that was more narrow and which excluded setter methods.
I've declared my aspects using the #Aspect annotation, but the advice does not seem to get applied. The aspect works in a few other projects that I have, and the key difference seems to be that the other projects are completely wired using annotations, and this particular project is xml wired. The only bean that is annotation wired is the Aspect. So I'm wondering if spring's aspectj support, when using aspectj-autoproxy is sensitive to order that the beans are defined in the xml.
For example, will beans declared after aspectj-autoproxy in xml be considered for AOP pointcuts?
EDIT:
I moved the <aop:aspectj-autoproxy /> until after all beans are created and still no luck.
Basically my code consists of:
#Component
#Aspect
public class SomeAspect {
#Pointcut("#annotation(MyAnnotation)")
public void isX() {}
#After("isX()")
public void XX() {
System.out.println("Called aspect");
}
}
And my controller has something like:
public class XController extends AbstractCommandController {
#MyAnnotation
public void handleX(...) {
// do stuff
}
#Override
protected void handle(...) {
return handleX(...);
}
}
And then the spring xml is:
<context:component-scan base-package="package.of.some.aspect" />
<aop:aspectj-autoproxy />
<!-- the rest of the beans below -->
<bean id="someController" class="..." />
My previous projects captured and loaded all beans via the component-scan. That's what's different this time.
EDIT2:
The other difference is that the other projects are using #Controller, and #RequestMethod. And in this case I'm using a derived class of AbstractCommmandController. I'm wondering if this applies:
http://forum.springsource.org/archive/index.php/t-46637.html
Namely that I can't apply advice to any method except handleRequest().
EDIT3:
My latest try is to override handleRequest() and apply my annotation there. Under the assumption that when spring proxies my controller it will see the annotation and apply the advice, since it's calling through the public, externally called method. This still doesn't work.
I see that you are calling the method handleX directly from another method in the same class. This will not respect the annotiation, as the work of processing AOP annotations is done by a JDK proxy that wraps your class and exposes the same interfaces.
It's possible that you can work around this by using CGLIB instead of JDK proxies, but in my experience, the most reliable solution is just not to rely on any AOP annotations for methods called internally.