Announcement Announcement Module
Collapse
No announcement yet.
Advice around annotation gets executed twice (AspectJ with LTW) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Advice around annotation gets executed twice (AspectJ with LTW)

    Hi,

    I am trying to add advice around an annotation. I want this advice to be applied to methods which are not directly called by the bean. Since Spring AOP cannot achieve this, I am using AspectJ with LTW. When I run this code the advice gets executed twice. Any ideas?

    Below is the code:

    This is the annotation class:
    Code:
    package com.test;
    
    import java.lang.annotation.Target;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface UpdatePrint {
    	String fields();
    }
    This is the aspect which executes around the annotation
    Code:
    package com.test;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class UpdatePrintAspect {
    
    	@Around("@annotation(updatePrint)")
    	public Object logPrint(ProceedingJoinPoint pjp, UpdatePrint updatePrint) throws Throwable{
    		
    		System.out.println("#### Start updating fields: " + updatePrint.fields());
    		
    		Object retVal = pjp.proceed();
    		
    		System.out.println("#### End Updating fields: " + updatePrint.fields());
    		
    		
    		return retVal;
    	}
    }
    This is the bean class:
    Code:
    package com.test;
    
    public class MyBean {
    		
    	public void update() {
    		updateTicker();
    		updateIssuer();
    	}
    
    	@UpdatePrint(fields="Issuer")
    	private void updateIssuer() {		
    		System.out.println("updateIssuer called");
    	}
    
    	@UpdatePrint(fields="Ticker")
    	private void updateTicker() {
    		System.out.println("updateTicker called");
    		
    	}
    
    }
    This is the driver class:
    Code:
    package com.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public final class Main {
    
        public static void main(String[] args) {
    
            ApplicationContext ctx = new ClassPathXmlApplicationContext("/beans.xml", Main.class);
    
            MyBean bean = (MyBean) ctx.getBean("myBean");
    
            bean.update();
        }
    }
    This is beans.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="
    		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    	<!-- this switches on the load-time weaving -->
        <context:load-time-weaver/>
    	   
        
        <bean id="myBean"
              class="com.test.MyBean"/>
    
       
    </beans>
    This is META-INF/aop.xml:
    Code:
    <aspectj>
        
        <aspects>        
            <aspect name="com.test.UpdatePrintAspect"/>
        </aspects>
    	
       
        <weaver options="-verbose">
            <include within="com.test.MyBean"/>
        </weaver>
    
    </aspectj>
    I get the following output:

    Dec 22, 2009 11:25:37 PM org.springframework.context.support.AbstractApplic ationContext prepareRefresh
    INFO: Refreshing org.springframework.context.support.ClassPathXmlAp plicationContext@1608e05: display name [org.springframework.context.support.ClassPathXmlAp plicationContext@1608e05]; startup date [Tue Dec 22 23:25:37 EST 2009]; root of context hierarchy
    Dec 22, 2009 11:25:37 PM org.springframework.beans.factory.xml.XmlBeanDefin itionReader loadBeanDefinitions
    INFO: Loading XML bean definitions from class path resource [/beans.xml]
    Dec 22, 2009 11:25:37 PM org.springframework.context.support.AbstractApplic ationContext obtainFreshBeanFactory
    INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlAp plicationContext@1608e05]: org.springframework.beans.factory.support.DefaultL istableBeanFactory@12f0999
    Dec 22, 2009 11:25:37 PM org.springframework.context.weaving.DefaultContext LoadTimeWeaver setBeanClassLoader
    INFO: Found Spring's JVM agent for instrumentation
    [AppClassLoader@130c19b] info AspectJ Weaver Version 1.6.5 built on Thursday Jun 18, 2009 at 03:42:32 GMT
    [AppClassLoader@130c19b] info register classloader sun.misc.Launcher$AppClassLoader@130c19b
    [AppClassLoader@130c19b] info using configuration /F:/Abhijeet/eclipse_workspace/SpringAspectJ1/lib/META-INF/aop.xml
    [AppClassLoader@130c19b] info register aspect com.test.UpdatePrintAspect
    Dec 22, 2009 11:25:38 PM org.springframework.beans.factory.support.DefaultL istableBeanFactory preInstantiateSingletons
    INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultL istableBeanFactory@12f0999: defining beans [org.springframework.context.weaving.AspectJWeaving Enabler#0,loadTimeWeaver,myBean]; root of factory hierarchy
    #### Start updating fields: Ticker
    #### Start updating fields: Ticker

    updateTicker called
    #### End Updating fields: Ticker
    #### End Updating fields: Ticker
    #### Start updating fields: Issuer
    #### Start updating fields: Issuer

    updateIssuer called
    #### End Updating fields: Issuer
    #### End Updating fields: Issuer

  • #2
    Code:
    @Aspect
    public class UpdatePrintAspect {
    
    	@Around("execution(* *(..)) && @annotation(updatePrint)")
    	public Object logPrint(ProceedingJoinPoint pjp, UpdatePrint updatePrint) throws Throwable{
    		
    		System.out.println("#### Start updating fields: " + updatePrint.fields());
    		
    		Object retVal = pjp.proceed();
    		
    		System.out.println("#### End Updating fields: " + updatePrint.fields());
    		
    		
    		return retVal;
    	}
    }

    Comment


    • #3
      Thanks a lot. It works!!

      Can you please tell me the concept behind why in the first case the advice was getting executed twice?

      Comment


      • #4
        Aspect Methods Are Not getting invoked

        I am new to Spring 2.5 and tried this example as practise. I checked at least twice if i have done everything correctly with the above example but whenever i run the Example the Advice/UpdatePrintAspect Methods are Not getting invoked.

        Below is what i see on the console. Can someone tell why the UpdatePrintAspect are not getting invoked. Rest of the configuration settings in aop.xml, beans.xml seems correct.

        Dec 26, 2009 6:41:01 AM org.springframework.context.support.AbstractApplic ationContext prepareRefresh
        INFO: Refreshing org.springframework.context.support.ClassPathXmlAp plicationContext@133f1d7: display name [org.springframework.context.support.ClassPathXmlAp plicationContext@133f1d7]; startup date [Sat Dec 26 06:41:01 SGT 2009]; root of context hierarchy
        Dec 26, 2009 6:41:01 AM org.springframework.beans.factory.xml.XmlBeanDefin itionReader loadBeanDefinitions
        INFO: Loading XML bean definitions from class path resource [beans.xml]
        Dec 26, 2009 6:41:01 AM org.springframework.context.support.AbstractApplic ationContext obtainFreshBeanFactory
        INFO: Bean factory for application context [org.springframework.context.support.ClassPathXmlAp plicationContext@133f1d7]: org.springframework.beans.factory.support.DefaultL istableBeanFactory@1ccce3c
        Dec 26, 2009 6:41:02 AM org.springframework.beans.factory.support.DefaultL istableBeanFactory preInstantiateSingletons
        INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultL istableBeanFactory@1ccce3c: defining beans [loadTimeWeaver,myBean]; root of factory hierarchy
        Dec 26, 2009 6:41:02 AM org.springframework.context.weaving.DefaultContext LoadTimeWeaver setBeanClassLoader
        INFO: Found Spring's JVM agent for instrumentation
        updateTicker called
        updateIssuer called

        Comment


        • #5
          Advice around annotation gets executed twice (AspectJ with LTW)

          It finally worked for me when i tried in a new project. But not sure what i was doing wrong earlier... Any comments will be appreciated

          Comment


          • #6
            Maybe META-INF/aop.xml was not in your classpath.

            Comment


            • #7
              Originally posted by abhijeetkh View Post
              Thanks a lot. It works!!

              Can you please tell me the concept behind why in the first case the advice was getting executed twice?
              If you run with weaver info turned on in your aop.xml, eg:

              Code:
              <weaver options="-showWeaveInfo">
              ... you'll see something like the following:

              Code:
              weaveinfo Join point 'method-call(void com.test.MyBean.updateIssuer())'
              weaveinfo Join point 'method-execution(void com.test.MyBean.updateIssuer())'
              Not an expert, but seems as though AspectJ makes a distinction between a method call and an execution, so you have to explicitly specify which one to use in the annotation attribute. Otherwise, as you and I both found out, it will use both!

              Comment


              • #8
                I had the same problem and adding "execution(* *(..)) &&" fixed it, thanks!

                Interesting that this double-weaving happens only if an annotated method is being called from another sibling method of the class.

                I.e. this will work as expected (woven once):

                Code:
                Class A {
                   @UpdatePrint
                   public void publicMethod() {
                      method2()
                   }
                
                   public void method2() {
                   }
                }
                But this one will have 2 invocations of the aspect:


                Code:
                Class A {
                   public void publicMethod() {
                      method2()
                   }
                
                   @UpdatePrint
                   public void method2() {
                   }
                }
                Does anybody know the mechanics and whether this inconsistency should be considered an AspectJ bug or not?

                Comment

                Working...
                X