转发:【干货】走进spring AOP源码,硬核解读切面的实现原理。其实底层逻辑就是代理类与方法链!!!
一.增强器的顺序
二.增强链顺序源码解析
可以得出如下结论
- 切面类之间的顺序:切面类没有@Order注解时默认顺位是Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE),有@Order注解则取里面的值,顺位小的先执行,执行原始方法时实际上是执行下个切面类或者原始bean方法
- 前后置增强方法之间的顺序:
无异常时:
@Around——joinPoint.proceed()之前
@Before
原始方法执行
@Around——joinPoint.proceed()之后
@After
@AfterReturning
有异常时:
@Around——joinPoint.proceed()之前
@Before
原始方法执行
@After
@AfterThrowing
下面,就让咱们去瞧瞧源码,验证下上面的结论
增强链顺序源码解析
核心逻辑在此方法中(创建bean的时候会判断是否有作用于当前bean的切面方法,有则该 bean实际创建的是代理类)
1.首先会找到所有有@Aspect注解的bean(按bean的注册顺序),然后遍历找到里面的增强方法,这里会对增强方法做一次排序,即上面总结的第2点逻辑,具体方法见
先找到class里没有@Pointcut注解的方法,然后通过METHOD_COMPARATOR排序
明显可以看出增强顺序为Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
2.从增强方法中找到能作用于当前bean的:具体逻辑就是取@Before(value="pointCut()")里的表达式,即execution(* *.doService(..))做校验,此处知道spring切面表达式的用法即可,深究没什么意义
3.拓展(可忽略)
4.增强方法整体排序:
其实就是使用Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator()来排序
AspectJPrecedenceComparator实现了Comparator接口,compare方法的逻辑就是先用AnnotationAwareOrderComparator比较(其实所有支持注解排序的都用的这个Comparator,比如@Configuration配置类也可以通过@Order排序,逻辑都是一样的),如果顺位一样且在同一切面类里,再执行comparePrecedenceWithinAspect方法,下面一个一个来分析。
注解排序比较器AnnotationAwareOrderComparator(源码略长,可直接看总结)
AnnotationAwareOrderComparator继承自OrderComparator
如果谁实现了PriorityOrdered接口,则优先排前面,都实现了或都没实现则调用getOrder方法获取顺位,getOrder又会调用getOrder(@Nullable Object obj)方法,又会调用findOrder方法

先调用super.findOrder,逻辑就是如果实现了Ordered接口,调用getOrder返回顺位,而看上图,obj实际是InstantiationModelAwarePointcutAdvisorImpl增强实现类,而该类实现了Ordered接口
再调用
再调用
可以看出是获取Aspect类的class,如果有实现Ordered接口,就getOrder获取顺位,否则通过OrderUtils.getOrder方法获取
逻辑就是,类若有@Order注解,获取配置的顺位,否则看类上是否有javax.annotation.Priority注解,获取配置的value,若都没有,则顺位为Ordered.LOWEST_PRECEDENCE
好了,终于把通过注解判断优先顺位(AnnotationAwareOrderComparator)的逻辑讲完了,总结下:
- 类实现了PriorityOrdered接口,则优先排前面(这里的类在本文中指的是Advisor增强类)
- 获取顺位值,小的排前面:切面类实现Ordered接口,从接口方法getOrder获取;切面类有@Order注解,获取注解value;切面类有javax.annotation.Priority注解,获取注解value。若都没有,则顺位为Ordered.LOWEST_PRECEDENCE(Integer.MAX_VALUE)
提示:写到这里其实已经“大概”验证了文章开头的结论,只是AnnotationAwareOrderComparator排完序后还有一段排序逻辑,会有点绕,而且要结合各个增强方法里的具体逻辑,但是最终呈现出的结果和上面排完序后其实一样,感兴趣的同学可以加把劲,继续看完,相信会对你大有裨益!!
AspectJPrecedenceComparator
再说回到AspectJPrecedenceComparator的compare方法
当通过AnnotationAwareOrderComparator比较完后,如果两个增强方法顺位相等且是一个切面类Aspect里的,则调用comparePrecedenceWithinAspect方法
首先判断两个增强方法里有没有后置增强(其实就是判断是不是这三类增强After, AfterReturning, AfterThrowing)
再调用getAspectDeclarationOrder获取各自的配置order做减法(其实就是获取Advisor实现类的declarationOrder属性,而该属性在创建Advisor的时候被设置,就是在第一步解析切面类所有增强方法时的顺序,比如around是0,before是1,after是2)
判断逻辑有点绕,反正最终排序完成后,顺序变成AfterThrowing,AfterReturning,After,Before,Around了,再把这个增强方法list当做属性设置到创建的代理类的Invocation中
除了Around和Before,其实就是相当于进行了倒序排序,为什么呢?因为spring把增强方法串成了一条增强链,越先执行的其增强逻辑(切面注解对应的方法)会越后执行
下面继续看service方法实际执行时的逻辑:
当执行service.doService("123");时,会执行Invocation里的方法,见下图
逻辑就是对增强方法list(上图中的interceptorsAndDynamicMethodMatchers)依次执行,根据上面排序的结果,一个个来解析
1.AspectJAfterThrowingAdvice
可以看到又执行了传参对象的proceed方法,即继续调用之前的方法去执行下个增强方法,但是加了一个try catch,所以如果有报错,会先判断异常类型是否匹配@AfterThrowing注解的throwing属性值,再反射调用@AfterThrowing注解对应的方法
2.AfterReturningAdviceInterceptor
和AfterThrowing如出一辙,也是先让增强链继续执行,然后执行@AfterReturning注解对应的方法(所以当原始方法报错时,AfterReturning不会执行)
3.AspectJAfterAdvice
和AfterReturning类似,区别在于这里是用try finally,无论有没有报错,都会执行After,而AfterReturning只有当不报错时才会执行
4.AspectJAroundAdvice
这里和之前的逻辑不太一样,没有执行mi.proceed()继续调用增强链,而是直接调用注解对应方法,但其实这行代码就在我们的业务代码中
ProxyMethodInvocation被封装成了ProceedingJoinPoint,然后传到注解对应方法的参数中,joinPoint.proceed()实际会调用this.methodInvocation.invocableClone().proceed()
5.MethodBeforeAdviceInterceptor
先执行@Before注解对应方法,再继续调用增强链
当所有增强方法都执行完后(currentInterceptorIndex初始值为-1),执行invokeJoinpoint调用原始方法

浙公网安备 33010602011771号