Search code examples
springaopaspectjapache-servicemix

How should aspect weaving be limited to classes referenced by aop:advisor pointcuts?


I'm trying to trace execution of an app running on ServiceMix 3.2 which uses spring 2.5 under the hood. I'm using CGLIB (advising classes, not interfaces) and I would like to direct tracing using pointcuts. I therefore configured spring to perform load-time weaving in one of my service unit xbean.xml files like so:

<bean id="debugInterceptor"
    class="org.springframework.aop.interceptor.SimpleTraceInterceptor"/>
<aop:config proxy-target-class="true">
    <aop:advisor advice-ref="debugInterceptor"
        pointcut="within(my.package.AClass)" order="1"/>
</aop:config>

Classes get advised, but it isn't limited to what I specified in the pointcut, i.e. methods of classes other than my.package.AClass get advised and, for reasons not important here, break class loading.

I tried defining the pointcut this way, but it made no difference:

<aop:advisor advice-ref="debugInterceptor"
    pointcut="execution(* my.package.AClass.*(..))" order="1"/>

In general, I would like to advise my.package..* classes except my.package.no_aop.*, but I don't seem to be making progress.

Why does CGLIB process classes outside of my.package.AClass? How do I prevent it? Would switching to Spring AOP (as opposed to AspectJ) make a difference?


Solution

  • I did it using Spring 3.0.x and @AspectJ annotations, but it should be analogous using 2.5 and XML.

    Class A from package my.pkg, that needs to be adviced:

    package my.pkg;
    
    public class ClassA {
    
        public void doFromClassA() {
            System.out.println("Hello from A!");
        }
    }
    

    Class B from package my.pkg.noaop, that needs not to be adviced:

    package my.pkg.noaop;
    
    public class ClassB {
    
        public void doFromClassB() {
            System.out.println("Hello from B!");
        }
    }
    

    The aspect:

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    
    @Aspect
    public class AopTestAspect {
    
        @Around("within(my.pkg..*) && !within(my.pkg.noaop..*)")
        public void advice(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("Hello from adviced!");
            pjp.proceed();
        }
    }
    

    The configuration (let me know if You need XML version):

    import my.pkg.ClassA;
    import my.pkg.noaop.ClassB;
    
    import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AopTestConfig {
    
        @Bean
        public ClassA classA() {
            return new ClassA();
        }
    
        @Bean
        public ClassB classB() {
            return new ClassB();
        }
    
        @Bean
        public AopTestAspect aspect() {
            return new AopTestAspect();
        }
    
        @Bean
        public AnnotationAwareAspectJAutoProxyCreator autoProxyCreator() {
            AnnotationAwareAspectJAutoProxyCreator autoProxyCreator = new AnnotationAwareAspectJAutoProxyCreator();
            autoProxyCreator.setProxyTargetClass(true);
            return autoProxyCreator;
        }
    }
    

    The test:

    import my.pkg.ClassA;
    import my.pkg.noaop.ClassB;
    
    import org.junit.Test;
    import org.springframework.beans.factory.BeanFactoryUtils;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class AopTest {
    
        @Test
        public void test() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
            applicationContext.register(AopTestConfig.class);
            applicationContext.refresh();
    
            ClassA a = BeanFactoryUtils.beanOfType(applicationContext, ClassA.class);
            ClassB b = BeanFactoryUtils.beanOfType(applicationContext, ClassB.class);
    
            a.doFromClassA();
            b.doFromClassB();
        }
    }
    

    And the output from the test:

    Hello from adviced!
    Hello from A!
    Hello from B!
    

    As You can see only the ClassA got adviced.

    Conclusion

    The key is the pointcut experssion:

    within(my.pkg..*) && !within(my.pkg.noaop..*)