切面执行顺序
说起这个切面执行顺序,我就想起一个之前遇到的挺有意思的问题,为啥@Around方法里面不手动调用joinPoint.proceed()方法,目标方法就不会执行,并且@Before方法的逻辑也不会执行?
我们先来看一下切面的执行顺序
一个方法被一个aspect类拦截时的执行顺序如下
@Around->@Before->方法执行->@Around->@After->@AfterReturning/@AfterThrowing
当方法正常结束时,执行@AfterReturning。方法异常结束时,执行@AfterThrowing
当多个切面同时执行时,我们可以实现Ordered接口,或者使用@Order注解指定顺序。order值越小,执行顺序越来越靠前
图中After,AfterReturning,AfterThrowing还是依次执行哈,放到一块是图片好看一点
JDK动态代理切面执行
我们只分析JdkDynamicAopProxy的执行过程,jdk动态代理的类所有方法的执行都会经过InvocationHandler#invoke方法,所以我们直接来分析invoker方法
JdkDynamicAopProxy#invoke(省略部分无关紧要的逻辑)
之前在生成代理对象的时候,我们把能够应用于当前Bean的Advisor存到advised,当方法执行的时候执行getInterceptorsAndDynamicInterceptionAdvice方法筛选出能够适用于当前方法的Advisor,并缓存下来
AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
如果方法没有对应的Advisor,则反射执行方法即可
如果方法有对应的Advisor,则执行ReflectiveMethodInvocation#proceed
ReflectiveMethodInvocation#proceed
感觉切面链念起来怪怪的,我们这里就叫做拦截器链把,这段的作用主要就是依次执行拦截器链然后执行目标方法。如果拦截器是InterceptorAndDynamicMethodMatcher的实现类,则动态匹配一下,看是否需要执行。
我们常用的AspectJ注解都是直接强转为MethodInterceptor,然后执行invoke方法。
我原来看到这段代码的时候还挺奇怪的,拦截器链执行完才执行被代理的方法,那@Around,@After之类的拦截器是怎么执行的?不应该放在目标方法执行完毕才执行吗?
于是写了如下一个Demo,把所有的拦截器都用上
执行的时候拦截器的顺序如下,
ExposeInvocationInterceptor是框架设置进去的,不管他了。我把调用的链路画了一下,这样所以的疑惑都解决了,源码我就不看了哈,简单的递归调用
图示中的proceed代表执行ReflectiveMethodInvocation#proceed方法哈
看到图示你应该明白了@Around里面不调用joinPoint.proceed()方法时,目标方法和@Before逻辑都不会执行的原因了把!
参考博客
[1]https://www.tianxiaobo.com/2018/06/22/Spring-AOP-%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E6%8B%A6%E6%88%AA%E5%99%A8%E9%93%BE%E7%9A%84%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B/
好文
[2]https://www.cnblogs.com/lifullmoon/p/14654883.html
顺序
[1]https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-ataspectj-advice-ordering
[2]https://www.cnblogs.com/csyh/articles/13246574.html
好文
[3]https://juejin.cn/post/6844903975578238984
[4]https://blog.csdn.net/nickyyu/article/details/105027203
[5]https://zhuanlan.zhihu.com/p/373973937
[6]https://www.cnblogs.com/tomakemyself/p/14131421.html
[7]https://my.oschina.net/u/2377110/blog/1536991