【Spring AOP】【九】Spring AOP源码解析-拦截器/通知器链的执行过程
1 前言
上一节我们说了通知器链的而顺序问题,那么这节我们该看看它的执行了。我们拿JDK代理的执行过程来看哈。
2 源码分析
2.1 方法通读
对于JDK动态代理的,那我们再回来看下当获取到要执行的通知器链后,要做什么呢,看源码:
// 创建方法调用器 并要执行的拦截器传进去 MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 执行拦截器链 也就是说proceed()这个方法里会循环调用或者递归调用 retVal = invocation.proceed();
可以看到创建了ReflectiveMethodInvocation这个对象:
protected ReflectiveMethodInvocation( Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; this.targetClass = targetClass; this.method = BridgeMethodResolver.findBridgedMethod(method); this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments); this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; }
那我们重点看下它的proceed()方法:
/** * 走到这里我们应该清楚 * interceptorsAndDynamicMethodMatchers 里边已经有了我们的拦截器并且是按顺序排好的 */ public Object proceed() throws Throwable { /** * currentInterceptorIndex起始值是-1 * 也就是说interceptorsAndDynamicMethodMatchers.size() - 1 表示拦截器都执行完了 * 该执行目标方法了 */ if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } // 拿出当前要执行的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { // Evaluate dynamic method matcher here: static part will already have // been evaluated and found to match. InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass()); // 方法匹配判断 匹配到就执行拦截器的invoke方法 并把this传过去了 也就是执行器链 这样那边就可以继续proceed()执行下一个拦截器咯 if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 匹配失败 继续proceed() 到下一个 return proceed(); } } else { // 执行拦截器逻辑,并传递 this return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
大致流程就是:从第一个通知器开始执行,直到最后一个通知器然后执行目标方法,那我们接下来看看这5类通知器,我按照通知器类型的顺序来哈。
2.2 @Around环绕通知-AspectJAroundAdvice
public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); JoinPointMatch jpm = getJoinPointMatch(pmi); // 执行环绕通知的增强 return invokeAdviceMethod(pjp, jpm, null, null); }
顺便我们拿来我们例子:
@Around("myPointCut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around before"); Object res = joinPoint.proceed(); System.out.println("around after"); return res; }
这时候我们是不是控制台会打印出:around before
执行过过程图:
看我们的例子接下来执行joinPoint.proceed(); 也就是要执行我们实际的目标方法,joinPoint其实还是我们的通知器链,那我们proceed()是不是继续执行下一个通知器么?是不是就到了前置通知了。
2.3 @Before前置通知-MethodBeforeAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); } @Override public void before(Method method, Object[] args, @Nullable Object target) throws Throwable { invokeAdviceMethod(getJoinPointMatch(), null, null); }
执行前置通知,然后继续proceed()继续下一个,这里我有三个前置通知器,所以跳过两个通知器哈,调到该我们的后置通知了。
2.4 @After后置通知-AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { // 继续下一个通知器 return mi.proceed(); } finally { // 调用通知方法 invokeAdviceMethod(getJoinPointMatch(), null, null); } }
@After("myPointCut()") public void myAfter(JoinPoint point) { System.out.println("myAfter"); }
可以看到finally里才会执行后置通知,也就是继续下一个通知器即返回通知,当通知器都执行完以及目标方法执行完时才会执行finally即后置通知,那我问问你后置通知执行完代码回到哪里了?
2.5 @AfterReturning返回通知-AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); return retVal; }
看返回通知,先执行下一个通知器即异常通知,当通知器都执行完以及目标方法执行完时才会执行finally即后置通知,那我问问你后置通知执行完代码又回到哪里了?
2.6 @AfterThrowing异常通知-AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable { try { return mi.proceed(); } catch (Throwable ex) { if (shouldInvokeOnThrowing(ex)) { invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } }
异常通知,看也是执行下一个通知器,已经到底了,所以执行目标方法。到这里了,问问你自己,下一步该执行什么了?是不是到返回通知了。
继续后置通知以及环绕通知结束。
ok到这里,我们的代理的一个执行过程就结束了,结合成代码可以看成这样:
// 环绕通知前 // 前置通知 try { // 返回通知 try { // 目标方法 } catch (Throwable var3) { // 异常通知 } } finally { // 后置通知 }
// 环绕通知后
3 小结
好了,到这里我们的代理执行过程也看的差不多了,整个AOP整体上的一个过程,也有了大致的理解,哪里有理解不对的地方欢迎指正哈,大家也可以试试多个Aspect的时候,通知器的顺序是怎么样的,执行的过程什么样的,加油。