上一篇博文中我们讲了代理类的生成,这一篇主要讲解剩下的部分,当代理类调用时,目标方法和代理方法是如何执行的,我们还是接着上篇的ReflectiveMethodInvocation类Proceed方法来看

public Object proceed() throws Throwable {
// 首先,判断是不是所有的interceptor(也可以想像成advisor)都被执行完了。
// 判断的方法是看currentInterceptorIndex这个变量的值,增加到Interceptor总个数这个数值没有,
// 如果到了,就执行被代理方法(invokeJoinpoint());如果没到,就继续执行Interceptor。
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
} // 如果Interceptor没有被全部执行完,就取出要执行的Interceptor,并执行。
// currentInterceptorIndex先自增
Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 如果Interceptor是PointCut类型
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
// 如果当前方法符合Interceptor的PointCut限制,就执行Interceptor
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
   // 这里将this当变量传进去,这是非常重要的一点
return dm.interceptor.invoke(this);
}
// 如果不符合,就跳过当前Interceptor,执行下一个Interceptor
else {
return proceed();
}
}
// 如果Interceptor不是PointCut类型,就直接执行Interceptor里面的增强。
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

我们先来看一张方法调用顺序图

我们看到链中的顺序是AspectJAfterThrowingAdvice、AfterReturningAdviceInterceptor、AspectJAfterAdvice、MethodBeforeAdviceInterceptor,这些拦截器是按顺序执行的,那我们来看看第一个拦截器AspectJAfterThrowingAdvice中的invoke方法

AspectJAfterThrowingAdvice

 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//直接调用MethodInvocation的proceed方法
//从proceed()方法中我们知道dm.interceptor.invoke(this)传过来的参数就是ReflectiveMethodInvocation执行器本身
//这里又直接调用了ReflectiveMethodInvocation的proceed()方法
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}

第一个拦截器AspectJAfterThrowingAdvice的invoke方法中,直接调用mi.proceed();,从proceed()方法中我们知道dm.interceptor.invoke(this)传过来的参数就是ReflectiveMethodInvocation执行器本身,所以又会执行proceed()方法,拦截器下标currentInterceptorIndex自增,获取下一个拦截器AfterReturningAdviceInterceptor,并调用拦截器中的invoke方法,,此时第一个拦截器在invoke()方法的第七行卡住了,接下来我们看第二个拦截器的执行

AfterReturningAdviceInterceptor

 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
//直接调用MethodInvocation的proceed方法
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}

AfterReturningAdviceInterceptor还是直接调用mi.proceed(),又回到了ReflectiveMethodInvocation的proceed()方法中,此时AfterReturningAdviceInterceptor方法卡在第四行,接着回到ReflectiveMethodInvocation的proceed()方法中,拦截器下标currentInterceptorIndex自增,获取下一个拦截器AspectJAfterAdvice,并调用AspectJAfterAdvice中的invoke方法

AspectJAfterAdvice

 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
//直接调用MethodInvocation的proceed方法
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

AspectJAfterAdvice还是直接调用mi.proceed(),又回到了ReflectiveMethodInvocation的proceed()方法中,此时AspectJAfterAdvice方法卡在第五行,接着回到ReflectiveMethodInvocation的proceed()方法中,拦截器下标currentInterceptorIndex自增,获取下一个拦截器MethodBeforeAdviceInterceptor,并调用MethodBeforeAdviceInterceptor中的invoke方法

MethodBeforeAdviceInterceptor

 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
//终于开始做事了,调用增强器的before方法,明显是通过反射的方式调用
//到这里增强方法before的业务逻辑执行
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
//又调用了调用MethodInvocation的proceed方法
return mi.proceed();
}

第5行代码终于通过反射调用了切面里面的before方法,接着又调用mi.proceed(),我们知道这是最后一个拦截器了,此时this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1应该为true了,那么就会执行 return invokeJoinpoint();,也就是执行bean中的目标方法,接着我们来看看目标方法的执行

@Nullable
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
} @Nullable
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable { // Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
//直接通过反射调用目标bean中的method
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}

before方法执行完后,就通过反射的方式执行目标bean中的method,并且返回结果,接下来我们想想程序该怎么执行呢?

1 、MethodBeforeAdviceInterceptor执行完了后,开始退栈,AspectJAfterAdvice中invoke卡在第5行的代码继续往下执行, 我们看到在AspectJAfterAdvice的invoke方法中的finally中第8行有这样一句话 invokeAdviceMethod(getJoinPointMatch(), null, null);,就是通过反射调用AfterAdvice的方法,意思是切面类中的 @After方法不管怎样都会执行,因为在finally中

 2、AspectJAfterAdvice中invoke方法发执行完后,也开始退栈,接着就到了AfterReturningAdviceInterceptor的invoke方法的第4行开始恢复,但是此时如果目标bean和前面增强器中出现了异常,此时AfterReturningAdviceInterceptor中第5行代码就不会执行了,直接退栈;如果没有出现异常,则执行第5行,也就是通过反射执行切面类中@AfterReturning注解的方法,然后退栈

3、AfterReturningAdviceInterceptor退栈后,就到了AspectJAfterThrowingAdvice拦截器,此拦截器中invoke方法的第7行开始恢复,我们看到在 catch (Throwable ex) { 代码中,也就是第11行 invokeAdviceMethod(getJoinPointMatch(), null, ex);,如果目标bean的method或者前面的增强方法中出现了异常,则会被这里的catch捕获,也是通过反射的方式执行@AfterThrowing注解的方法,然后退栈

总结

这个代理类调用过程,我们可以看到是一个递归的调用过程,通过ReflectiveMethodInvocation类中Proceed方法递归调用,顺序执行拦截器链中AspectJAfterThrowingAdvice、AfterReturningAdviceInterceptor、AspectJAfterAdvice、MethodBeforeAdviceInterceptor这几个拦截器,在拦截器中反射调用增强方法

 

最新文章

  1. stanford NLP学习笔记3:最小编辑距离(Minimum Edit Distance)
  2. swift 键盘属性与事件
  3. bootstrap学习总结-js组件(四)
  4. HDU4456-Crowd(坐标旋转+二位树状数组+离散化)
  5. WebDriver(Selenium2) 常见异常及处理方法
  6. android学习10——对顶点着器和片段着色器的理解
  7. git-ftp 用git管理ftp空间
  8. quartz 时间设置(定时任务scheduler)
  9. MySql 动态语句
  10. C#中IPAddress转换成整型int
  11. Bootstrap常用单词组
  12. 今天捡起来python
  13. loadrunner---Android、iOS压力测试
  14. [SQL]事务回滚详解及示例
  15. kbmmw 5.08 正式发布
  16. gridView 删除一行后自动定位到指定行
  17. 分布式缓存技术redis系列(四)——redis高级应用(集群搭建、集群分区原理、集群操作)
  18. 省市区三级联动——思路、demo、示例
  19. git 将本地仓库提交至github
  20. 廖雪峰Java1-4数组操作-5命令行参数

热门文章

  1. Joyful HDU - 5245 概率问题
  2. 2018年全国多校算法寒假训练营练习比赛(第五场)H Tree Recovery
  3. codeforces 591 E. Three States(bfs+思维)
  4. hdu 4081 Qin Shi Huang's National Road System(次小生成树prim)
  5. 微信小程序一步一步获取UnionID,实现自动登录
  6. 【Redis】哨兵机制
  7. (六十五)c#Winform自定义控件-图标字体
  8. angular关于Bootstrap样式不起作用问题
  9. Salesforce LWC学习(七) Navigation & Toast
  10. 让Jenkins执行GitHub上的pipeline脚本