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

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

作者: 天还下着毛毛雨 | 来源:发表于2023-03-18 11:05 被阅读0次

上一篇讲了,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

相关文章

网友评论

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

      本文链接:https://www.haomeiwen.com/subject/zumsrdtx.html