基础代码
/**
* <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 的前面