以 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 的前面

评论栏