以 Annotation 执行顺序来探究 AOP

    基础代码

    /**
     * <Description> Description for A <br>
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface A {
    
    }
    
    
    
    /**
     * <Description> Description for B <br>
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface B {
    
    }
    
    
    
    /**
     * <Description> Description for 注解顺序 <br>
     */
    @Component
    public class AnnotationOrderDemo extends AbstractDemoFactory {
    
        @A
        @B
        public void testABeforeB() {
    
        }
    
        @B
        @A
        public void testAAfterB() {
    
        }
    }
    
    
    
    @Component
    @Aspect
    public class AspectA {
    
        /**
         * logger
         */
        private static final Logger LOGGER = LoggerFactory.getLogger(AspectA.class);
    
        @Around("@annotation(com.jansora.demo.annotation.lib.annotation.A)")
        public Object a(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            LOGGER.debug("aspect a.");
            return proceedingJoinPoint.proceed();
        }
    
    
        @Around("@annotation(com.jansora.demo.annotation.lib.annotation.B)")
        public Object b(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            LOGGER.debug("aspect b.");
            return proceedingJoinPoint.proceed();
        }
    
    }
    
    
    
    
    @SpringBootApplication
    public class AnnotationApplication implements ApplicationRunner {
    
        @Autowired
        AnnotationOrderDemo annotationOrderDemo;
    
        private String[] args;
    
        public static void main(String[] args) throws Throwable {
            SpringApplication.run(AnnotationApplication.class, args);
        }
    
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            this.args = args.getSourceArgs();
            System.out.println("testABeforeB: ");
            annotationOrderDemo.testABeforeB();
            System.out.println("testAAfterB: ");
            annotationOrderDemo.testAAfterB();
        }
    }
    
    

    默认情况(不作任何干预)

    执行结果

    2022-08-04 11:03:11.429  INFO 32664 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 19932 (http) with context path ''
    2022-08-04 11:03:11.443  INFO 32664 --- [  restartedMain] c.j.d.annotation.AnnotationApplication   : Started AnnotationApplication in 2.217 seconds (JVM running for 2.65)
    testABeforeB: 
    2022-08-04 11:03:11.449 DEBUG 32664 --- [  restartedMain] c.j.demo.annotation.lib.aspect.AspectA   : aspect a.
    2022-08-04 11:03:11.450 DEBUG 32664 --- [  restartedMain] c.j.demo.annotation.lib.aspect.AspectA   : aspect b.
    testAAfterB: 
    2022-08-04 11:03:11.454 DEBUG 32664 --- [  restartedMain] c.j.demo.annotation.lib.aspect.AspectA   : aspect a.
    2022-08-04 11:03:11.454 DEBUG 32664 --- [  restartedMain] c.j.demo.annotation.lib.aspect.AspectA   : aspect b.
    

    结论: 不管 A 在 B 前, 还是 A 在 B 后, 默认情况下显示, A 的执行顺序都在 B 前.

    那么问题来了

    问题 1: 为什么两次执行结果不一致?

    问题 2: 为什么两次执行结果都是 A 在 B 前, 而不是 B 在 A 前?

    带着这两个问题, 我们来 DEBUG 一下

    栈快照

    b:30, AspectA (com.jansora.demo.annotation.lib.aspect)
    invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:77, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
    invoke:568, Method (java.lang.reflect)
    invokeAdviceMethodWithGivenArgs:634, AbstractAspectJAdvice (org.springframework.aop.aspectj)
    invokeAdviceMethod:624, AbstractAspectJAdvice (org.springframework.aop.aspectj)
    invoke:72, AspectJAroundAdvice (org.springframework.aop.aspectj)
    proceed:175, ReflectiveMethodInvocation (org.springframework.aop.framework)
    proceed:763, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
    proceed:89, MethodInvocationProceedingJoinPoint (org.springframework.aop.aspectj)
    a:23, AspectA (com.jansora.demo.annotation.lib.aspect)
    invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:77, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
    invoke:568, Method (java.lang.reflect)
    invokeAdviceMethodWithGivenArgs:634, AbstractAspectJAdvice (org.springframework.aop.aspectj)
    invokeAdviceMethod:624, AbstractAspectJAdvice (org.springframework.aop.aspectj)
    invoke:72, AspectJAroundAdvice (org.springframework.aop.aspectj)
    proceed:175, ReflectiveMethodInvocation (org.springframework.aop.framework)
    proceed:763, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
    invoke:97, ExposeInvocationInterceptor (org.springframework.aop.interceptor)
    proceed:186, ReflectiveMethodInvocation (org.springframework.aop.framework)
    proceed:763, CglibAopProxy$CglibMethodInvocation (org.springframework.aop.framework)
    intercept:708, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
    testABeforeB:-1, AnnotationOrderDemo$$EnhancerBySpringCGLIB$$74681490 (com.jansora.demo.annotation.lib)
    run:36, AnnotationApplication (com.jansora.demo.annotation)
    callRunner:762, SpringApplication (org.springframework.boot)
    callRunners:752, SpringApplication (org.springframework.boot)
    run:315, SpringApplication (org.springframework.boot)
    run:1306, SpringApplication (org.springframework.boot)
    run:1295, SpringApplication (org.springframework.boot)
    main:28, AnnotationApplication (com.jansora.demo.annotation)
    invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:77, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
    invoke:568, Method (java.lang.reflect)
    run:49, RestartLauncher (org.springframework.boot.devtools.restart)
    

    问题 1: 为什么两次执行结果不一致?

    问题 2: 为什么两次执行结果都是 A 在 B 前, 而不是 B 在 A 前?

    在跟踪完源代码后, 我们发现这两个问题可以合并为一个来解决,

    在 spring boot 应用启动时, 初始化每个单例 bean 时, 也会初始化它的 advisor.

    我们先保存一下跟踪到的栈

    getAdvisors:145, ReflectiveAspectJAdvisorFactory (org.springframework.aop.aspectj.annotation)
    buildAspectJAdvisors:110, BeanFactoryAspectJAdvisorsBuilder (org.springframework.aop.aspectj.annotation)
    findCandidateAdvisors:95, AnnotationAwareAspectJAutoProxyCreator (org.springframework.aop.aspectj.annotation)
    shouldSkip:101, AspectJAwareAdvisorAutoProxyCreator (org.springframework.aop.aspectj.autoproxy)
    postProcessBeforeInstantiation:255, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
    applyBeanPostProcessorsBeforeInstantiation:1160, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    resolveBeforeInstantiation:1135, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    createBean:531, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    lambda$doGetBean$0:335, AbstractBeanFactory (org.springframework.beans.factory.support)
    getObject:-1, AbstractBeanFactory$$Lambda$312/0x0000000800df2f00 (org.springframework.beans.factory.support)
    getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
    doGetBean:333, AbstractBeanFactory (org.springframework.beans.factory.support)
    getBean:208, AbstractBeanFactory (org.springframework.beans.factory.support)
    instantiateUsingFactoryMethod:410, ConstructorResolver (org.springframework.beans.factory.support)
    instantiateUsingFactoryMethod:1352, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    createBeanInstance:1195, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    doCreateBean:582, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    createBean:542, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    lambda$doGetBean$0:335, AbstractBeanFactory (org.springframework.beans.factory.support)
    getObject:-1, AbstractBeanFactory$$Lambda$312/0x0000000800df2f00 (org.springframework.beans.factory.support)
    getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
    doGetBean:333, AbstractBeanFactory (org.springframework.beans.factory.support)
    getBean:213, AbstractBeanFactory (org.springframework.beans.factory.support)
    findAdvisorBeans:91, BeanFactoryAdvisorRetrievalHelper (org.springframework.aop.framework.autoproxy)
    findCandidateAdvisors:111, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)
    findCandidateAdvisors:92, AnnotationAwareAspectJAutoProxyCreator (org.springframework.aop.aspectj.annotation)
    shouldSkip:101, AspectJAwareAdvisorAutoProxyCreator (org.springframework.aop.aspectj.autoproxy)
    postProcessBeforeInstantiation:255, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)
    applyBeanPostProcessorsBeforeInstantiation:1160, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    resolveBeforeInstantiation:1135, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    createBean:531, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
    lambda$doGetBean$0:335, AbstractBeanFactory (org.springframework.beans.factory.support)
    getObject:-1, AbstractBeanFactory$$Lambda$312/0x0000000800df2f00 (org.springframework.beans.factory.support)
    getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
    doGetBean:333, AbstractBeanFactory (org.springframework.beans.factory.support)
    getBean:213, AbstractBeanFactory (org.springframework.beans.factory.support)
    registerBeanPostProcessors:270, PostProcessorRegistrationDelegate (org.springframework.context.support)
    registerBeanPostProcessors:762, AbstractApplicationContext (org.springframework.context.support)
    refresh:567, AbstractApplicationContext (org.springframework.context.support)
    refresh:734, SpringApplication (org.springframework.boot)
    refreshContext:408, SpringApplication (org.springframework.boot)
    run:308, SpringApplication (org.springframework.boot)
    run:1306, SpringApplication (org.springframework.boot)
    run:1295, SpringApplication (org.springframework.boot)
    main:28, AnnotationApplication (com.jansora.demo.annotation)
    invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:77, NativeMethodAccessorImpl (jdk.internal.reflect)
    invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
    invoke:568, Method (java.lang.reflect)
    run:49, RestartLauncher (org.springframework.boot.devtools.restart)
    

    这里贴出关键的两步


    org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors 方法体内

    for (Method method : getAdvisorMethods(aspectClass)) { 这一行会根据 getAdvisorMethods 获取当前类的 method 来生成 advisor

    在这里我们先得到的是 A , 然后是 B. 导致了后续切面先走 A 切面, 后走 B 切面.

    org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisorMethods 方法体内, 这里对生成的 methods 顺序进行了手动排序, 排序类是 adviceMethodComparator

    找到 adviceMethodComparator 的赋值地方,

    我们发现是了是根据 method 的名称排序, 这里的 method 指的就是注解的名称, A 和 B, 因此 A 的切面 一直执行在 B 的前面

    评论栏