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

5. 代理执行链的调用
如果没找到匹配该方法的切面集合,那么就返回调用原方法

找到了,就匹配该方法的切面集合,就进行切面执行链的调用
会先创建一个代理执行上下文对象MethodInvocation,把所有的切面,代理对象,原生方法,参数,等等传进去

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

测试代码
为了更直观的 描述切面执行链的调用过程,这里准备点测试代码,把五种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();
}

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

可以看到有有一个默认的切面,加我们自己配置的五个切面:按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 注解所对应的切面类 排序。
然后这里有个currentInterceptorIndex变量,默认为-1, 来控制 从数组取出切面的下标。++后从数组取出切面对象。++后为0。

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

这里千万要注意,在调用 实现MethodInterceptor接口的所有切面实现类的invoke方法时会传入this,也就是当前MethodInvocation对象
ExposeInvocationInterceptor.invoke()
在 把MethodInvocation对象对象放入到ExposeInvocationInterceptor的 ThreadLocal<MethodInvocation> invocation后

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

2.执行AspectJAroundAdvice
上一轮取出ExposeInvocationInterceptor后, currentInterceptorIndex 已经被++成0了,这里++ = 1,取出下边为1的切面对象 : AspectJAroundAdvice
AspectJAroundAdvice用来处理@Around注解的

AspectJAroundAdvice.invoke

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

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

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

@Around注解下,我们一般会把增强的逻辑代码写在point.proceed()前后
point.proceed()方法 就又会递归到MethodInvocation的procceed()方法,把切面执行链传递下去。
千万注意,此时这个方法 还未出栈,也就是 point.proceed()方法后的方法 还要等 point.proceed()方法执行完后再执行。

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

3.执行MethodBeforeAdviceInterceptor
上一轮取出AspectJAroundAdvice后, currentInterceptorIndex 已经被++成1了,这里++ = 2,取出下边为2的切面对象 : MethodBeforeAdviceInterceptor
MethodBeforeAdviceInterceptor用来处理@Before注解的

MethodBeforeAdviceInterceptor.invoke
这里处理@Before注解的AspectJMethodBeforeAdvice类 是经过适配的,由MethodBeforeAdviceInterceptor持有它,
MethodBeforeAdviceInterceptor.invoke会 先调用AspectJMethodBeforeAdvice的before(),去调用@Before的方法


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

MyAspect.before()调用

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

代码回到这里MethodInvocation.proceed()

4.执行 AspectJAfterAdvice
上一轮取出AspectJAroundAdvice后, currentInterceptorIndex 已经被++成2了,这里++ = 3,取出下边为3的切面对象 : AspectJAfterAdvice
AspectJAfterAdvice用来处理@After注解的

AspectJAfterAdvice.invoke(mi)
@After切面的处理逻辑就有点奇特了,他先调用MethodInvocation的proceed(),把执行链传递下去,
再在finally代码块去 调用@After方法,也就是会等剩下的 @AfterReturning,@AfterThrowing切面执行完 以及原生方法 执行完,再去调用 调用@After方法

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

5.执行 AfterReturningAdviceInterceptor
上一轮取出AspectJAfterAdvice后, currentInterceptorIndex 已经被++成3了,这里++ = 4,取出下标为4的切面对象 : AfterReturningAdviceInterceptor
AfterReturningAdviceInterceptor用来处理@AfterReturning注解的

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

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

6.执行AspectJAfterThrowingAdvice
上一轮取出AfterReturningAdviceInterceptor后, currentInterceptorIndex 已经被++成4了,这里++ = 5,取出下标为5的切面对象 : AfterReturningAdviceInterceptor
AfterReturningAdviceInterceptor用来处理@AfterThrowing注解的

AspectJAfterThrowingAdvice.invoke(md)
@AfterThrowing注解的作用就是 原生方法执行时抛出异常后,再执行@AfterThrowing方法,并传入异常对象并进行处理增强,所以这里原生方法还没调用,
所以先try_catch, 先调用MethodInvocation的proceed方法,把执行链传递下去,等原生方法调用抛出异常时,catch到异常,再执行 invokeAdviceMethod方法 ,去调用@AfterThrowing的方法。

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

7.调用原生方法
我们一开始就只有6个切面,当上一个切面执行AspectJAfterThrowingAdvice 被取出时,currentInterceptorIndex被++,已经从4变到5了,所以再次进入MethodInvocation的proceed,会判断所以切面是否被执行完
判断 currentInterceptorIndex 是否等于 切面数组长度 -1,等于的话,说明所有切面都已经被调用了。

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

invokeJoinpoint()反射调用原生方法
就是反射调用 原生方法

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

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

然后方法结束
8.AspectJAfterThrowingAdvice.invoke(md)出栈
之前最后一次进入MethodInvocation.proceed()是在 AspectJAfterThrowingAdvice.invoke(md) 时,方法内部 调用的,所以,这里原生方法被执行return 后,回到 AspectJAfterThrowingAdvice.invoke(md)
这里没抛出异常,所以不会走catch里面的逻辑 : 判断抛出异常是否等于 @AfterThrowing里配置的异常,是的话,就调用@AfterThrowing方法,传入异常对象

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

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

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

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


然后@AfterReturning方法返回
AfterReturningAdviceInterceptor.invoke返回

ReflectiveMethodInvocation.invoke方法返回

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

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

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


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

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

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

接着执行point.proceed() 后面的代码,结束@Around方法
然后代码回到 调用@Around方法的AspectJAroundAdvice.invoke方法

MethodInvocation.proceed() return

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

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

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

网友评论