【Spring源码】25.AOP之代理执行时切面的链式调用

上一篇讲了,aop代理执行时,所有匹配该方法的切面都已经收集完毕,接下来就是 以责任链的模式 去遍历切面集合,来挨个增强原生方法。

image.png

5. 代理执行链的调用

如果没找到匹配该方法的切面集合,那么就返回调用原方法

image.png

找到了,就匹配该方法的切面集合,就进行切面执行链的调用

会先创建一个代理执行上下文对象MethodInvocation,把所有的切面,代理对象,原生方法,参数,等等传进去

image.png

然后调用MethodInvocation对象的proceed()方法,jdk动态代理实现用的是ReflectiveMethodInvocation类

image.png

测试代码

为了更直观的 描述切面执行链的调用过程,这里准备点测试代码,把五种aop方法代理类型的注解都加上

被代理的类和被代理的方法

@Component
public class MyBeanServiceImpl implements MyBeanService {
    @Override
    public String testMyBean() {
        System.out.println("原生方法被执行...");
        return "MyBeanServiceImpl.testMyBean方法的返回值";
    }
}

aop配置类

aop配置类,五种aop代理类型的类型都加上

@Aspect
@Component
public class MyAspect {

    @Pointcut("execution(* com.lb.springboot_simple_starter.bean.aop.service.impl.MyBeanServiceImpl.*(..))")
    public void pc2() {}

    @Before(" pc2()")
    public void before() {
        System.out.println("前置通知");
    }

    @After(" pc2()")
    public void after() {
        System.out.println("后置通知");
    }

    @Around("pc2()")
    public void around(ProceedingJoinPoint point) {
        System.out.println("环绕通知,原方法执行前");
        try {
            System.out.println("环绕通知中:" + point.proceed());
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕通知,原方法执行后");
    }

    @AfterThrowing(value = " pc2()", throwing = "e")
    public void AfterThrowing(Exception e) {
        System.out.println("异常通知");
        MethodInvocation methodInvocation = ExposeInvocationInterceptor.currentInvocation();
        e.printStackTrace();
    }

    @AfterReturning(value = "pc2()", returning = "result")
    public void doAfterReturning(Object result) {
        System.out.println("【返回后通知】 返回值:" + result);
    }
}

运行;

从spring容器中获取MyBeanService代理对象,并调用testMyBean()。

@Test
public void testGeneratorAdvisor(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.lb.springboot_simple_starter.bean.aop");
    MyBeanService bean = applicationContext.getBean(MyBeanService.class);
    bean.testMyBean();
    System.out.println(bean);
    //MyService bean = applicationContext.getBean(MyService.class);
    //bean.getUser();
}
image.png

ReflectiveMethodInvocation.proceed().

接下来,所有切面与当前执行方法匹配后,进入ReflectiveMethodInvocation.proceed()

image.png

可以看到有有一个默认的切面,加我们自己配置的五个切面:按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解所对应的切面类 排序。

然后这里有个currentInterceptorIndex变量,默认为-1, 来控制 从数组取出切面的下标。++后从数组取出切面对象。++后为0。

image.png

1.执行ExposeInvocationInterceptor

currentInterceptorIndex 初始为0,取出数组0下标对应的切面类 ExposeInvocationInterceptor对象

image.png

这里千万要注意,在调用 实现MethodInterceptor接口的所有切面实现类的invoke方法时会传入this,也就是当前MethodInvocation对象

ExposeInvocationInterceptor.invoke()

在 把MethodInvocation对象对象放入到ExposeInvocationInterceptor的 ThreadLocal<MethodInvocation> invocation后

image.png

调用当前MethodInvocation对象.proceed()方法,进行递归,代码又回到了这个

image.png

2.执行AspectJAroundAdvice

上一轮取出ExposeInvocationInterceptor后, currentInterceptorIndex 已经被++成0了,这里++ = 1,取出下边为1的切面对象 : AspectJAroundAdvice

AspectJAroundAdvice用来处理@Around注解的

image.png

AspectJAroundAdvice.invoke

image.png

调用AspectJAroundAdvice类的父类 AbstractAspectJAdvice的invokeAdviceMethod方法

这里注意下父类 AbstractAspectJAdvice的invokeAdviceMethod方法 是专门用来执行 增强逻辑的方法,也就是有@Around,@Before,@After,@AfterReturning,@AfterThrowing 的方法。切面对象 是会存有 对应方法的Method对象

image.png

然后反射调用 有@Around注解的方法

image.png

这样就会被调用到我们自己写的@Around方法。

image.png

@Around注解下,我们一般会把增强的逻辑代码写在point.proceed()前后

point.proceed()方法 就又会递归到MethodInvocation的procceed()方法,把切面执行链传递下去。

千万注意,此时这个方法 还未出栈,也就是 point.proceed()方法后的方法 还要等 point.proceed()方法执行完后再执行。

image.png

接下来代码又会回到MethodInvocation的procceed()。

image.png

3.执行MethodBeforeAdviceInterceptor

上一轮取出AspectJAroundAdvice后, currentInterceptorIndex 已经被++成1了,这里++ = 2,取出下边为2的切面对象 : MethodBeforeAdviceInterceptor

MethodBeforeAdviceInterceptor用来处理@Before注解的

image.png

MethodBeforeAdviceInterceptor.invoke

这里处理@Before注解的AspectJMethodBeforeAdvice类 是经过适配的,由MethodBeforeAdviceInterceptor持有它,

MethodBeforeAdviceInterceptor.invoke会 先调用AspectJMethodBeforeAdvice的before(),去调用@Before的方法

image.png
image.png

这里由会调用到公用的 父类AbstractAspectJAdvice去执行advise对象里面 的增强方法,返回调用@Before方法

image.png

MyAspect.before()调用

image.png

接下来该方法结束,

代码回到 MethodBeforeAdviceInterceptor.invoke方法,又调用MethodInvocation得proceed(),把执行链传递下去

image.png

代码回到这里MethodInvocation.proceed()

image.png

4.执行 AspectJAfterAdvice

上一轮取出AspectJAroundAdvice后, currentInterceptorIndex 已经被++成2了,这里++ = 3,取出下边为3的切面对象 : AspectJAfterAdvice

AspectJAfterAdvice用来处理@After注解的

image.png

AspectJAfterAdvice.invoke(mi)

@After切面的处理逻辑就有点奇特了,他先调用MethodInvocation的proceed(),把执行链传递下去,

再在finally代码块去 调用@After方法,也就是会等剩下的 @AfterReturning,@AfterThrowing切面执行完 以及原生方法 执行完,再去调用 调用@After方法

image.png

这里AspectJAfterAdvice.invoke还没出栈,先把执行链传递下去,代码又回到MethodInvocation.proceed()

image.png

5.执行 AfterReturningAdviceInterceptor

上一轮取出AspectJAfterAdvice后, currentInterceptorIndex 已经被++成3了,这里++ = 4,取出下标为4的切面对象 : AfterReturningAdviceInterceptor

AfterReturningAdviceInterceptor用来处理@AfterReturning注解的

image.png

AfterReturningAdviceInterceptor.invoke(mi)

这里处理@AfterReturning注解的AfterReturningAdvice类 是经过适配的,由AfterReturningAdviceInterceptor.invoke持有它,

AfterReturningAdviceInterceptor.invoke可以调用AfterReturningAdvice的afterReturning(),去调用@AfterReturning的方法。

@AfterReturning注解的作用就是 等原生方法返回之后,再执行@AfterReturning方法,所以这里原生方法还没调用,更不会有返回值,所以把执行链传递下去,等剩下的@AfterThrowing注解处理完,原生方法调用完获取到返回值之后,再执行 AfterReturningAdvice的afterReturning(),去调用@AfterReturning的方法。

image.png

这里AfterReturningAdviceInterceptor.invoke(mi)还没出栈,先把执行链传递下去,代码又回到MethodInvocation.proceed()

image.png

6.执行AspectJAfterThrowingAdvice

上一轮取出AfterReturningAdviceInterceptor后, currentInterceptorIndex 已经被++成4了,这里++ = 5,取出下标为5的切面对象 : AfterReturningAdviceInterceptor

AfterReturningAdviceInterceptor用来处理@AfterThrowing注解的

image.png

AspectJAfterThrowingAdvice.invoke(md)

@AfterThrowing注解的作用就是 原生方法执行时抛出异常后,再执行@AfterThrowing方法,并传入异常对象并进行处理增强,所以这里原生方法还没调用,

所以先try_catch, 先调用MethodInvocation的proceed方法,把执行链传递下去,等原生方法调用抛出异常时,catch到异常,再执行 invokeAdviceMethod方法 ,去调用@AfterThrowing的方法。

image.png

所以这里,代码又回到了MethodInvocation的proceed方法,注意此时AspectJAfterThrowingAdvice.invoke方法 并未出栈

image.png

7.调用原生方法

我们一开始就只有6个切面,当上一个切面执行AspectJAfterThrowingAdvice 被取出时,currentInterceptorIndex被++,已经从4变到5了,所以再次进入MethodInvocation的proceed,会判断所以切面是否被执行完

判断 currentInterceptorIndex 是否等于 切面数组长度 -1,等于的话,说明所有切面都已经被调用了。

image.png

所有切面被调用了,那么接下来就只有调用原生方法了,也就是被代理方法

image.png

invokeJoinpoint()反射调用原生方法

就是反射调用 原生方法

image.png

传入被代理方法,反射调用method


image.png

进入我们的原生方法,返回返回值,不抛出异常

image.png

然后方法结束

8.AspectJAfterThrowingAdvice.invoke(md)出栈

之前最后一次进入MethodInvocation.proceed()是在 AspectJAfterThrowingAdvice.invoke(md) 时,方法内部 调用的,所以,这里原生方法被执行return 后,回到 AspectJAfterThrowingAdvice.invoke(md)

这里没抛出异常,所以不会走catch里面的逻辑 : 判断抛出异常是否等于 @AfterThrowing里配置的异常,是的话,就调用@AfterThrowing方法,传入异常对象

image.png

这里return出去后,ReflectiveMethodInvocation.proceed 也return

image.png

9.AfterReturningAdviceInterceptor.invoke(md)出栈

调用AspectJAfterThrowingAdvice.invoke的MethodInvocation.proceed ()是由AfterReturningAdviceInterceptor.invoke(mi)调用的,所以MethodInvocation.proceed () 返回后,代码回到 AspectJAfterThrowingAdvice.invoke(md)

image.png

接下来调用AfterReturningAdvice的afterReturning方法,去调用@AfterReturning方法

image.png

invokeAdviceMethod肯定又是公用父类AbstractAspectJAdvice里面的,反射调用AfterReturningAdvice对象里存储的@@AfterReturning方法 的Method对象,并传入返回值

image.png
image.png

然后@AfterReturning方法返回

AfterReturningAdviceInterceptor.invoke返回

image.png

ReflectiveMethodInvocation.invoke方法返回

image.png

10. AspectJAfterAdvice.invoke出栈

代码回到上一个调用 MethodInvocation.invoke()方法的AspectJAfterAdvice.invoke()方法内

image.png

然后在finally块调用invokeAdviceMethod() ,invokeAdviceMethod()肯定又是公用父类AbstractAspectJAdvice里面的,去调用@After方法的Method对象,这里就不赘述了,直接进入到@After方法

这里和@AfterReturning方法的区别就是不在乎返回值

image.png

然后AspectJAfterAdvice.invoke出栈,调用它的 MethodInvocation.invoke()也随之出栈

image.png
image.png

12.MethodBeforeAdviceInterceptor.invoke(md)出栈

代码回到上一个 调用 MethodInvocation.proceed()的 MethodBeforeAdviceInterceptor.invoke(md)里

image.png

这里MethodInvocation.proceed(),MethodBeforeAdviceInterceptor.invoke(md)也return,又回到 MethodInvocation.proceed() 去return

image.png

13.@Around方法出栈

上一次调用MethodInvocation.proceed() 是在我们@Around方法的内部,手动调用的,所以MethodInvocation.proceed() return后 代码又回到这,

image.png

接着执行point.proceed() 后面的代码,结束@Around方法

然后代码回到 调用@Around方法的AspectJAroundAdvice.invoke方法

image.png

MethodInvocation.proceed() return

image.png

14.ExposeInvocationInterceptor出栈

代码回到最初 调用MethodInvocation.proceed()的 ExposeInvocationInterceptor.invoke中

直接return 执行完 MethodInvocation.proceed() 后执行finally, 把旧的 aop代理执行上下文 设置回去 ,方法结束,ExposeInvocationInterceptor.inoke方法也随之出栈结束了。

image.png

15.JdkDynamicAopProxy.invoke 出栈

至此,所有的aop切面执行完了, JdkDynamicAopProxy 这个InvokeHandler的 invoke方法执行完,返回返回值,代理对象的代理逻辑也就彻底走完了。

image.png

代理对象的方法 调用就彻底完成了

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容