Spring-AOP源碼分析隨手記(二)

這次來(lái)分析下切面的執(zhí)行過(guò)程。

1.怎么看?

怎么開(kāi)始看源碼呢?就直接從被增強(qiáng)的方法調(diào)用那里打斷點(diǎn),看看怎么執(zhí)行的:

image

然后就來(lái)到了這:

image
image

2.初步分析

里面有段:

if (this.advised.exposeProxy) {
   // Make invocation available if necessary.
   oldProxy = AopContext.setCurrentProxy(proxy);
   setProxyContext = true;
}

就是上篇文章講到的注解配置暴露代理對(duì)象,放到AopContext的ThreadLocal里去,之后就可以隨時(shí)用 AopContext.currentProxy())取到代理對(duì)象。

接下來(lái)有段重要的:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

獲取攔截器鏈,就是把這次相關(guān)的增強(qiáng)器轉(zhuǎn)化成攔截器獲取出來(lái)

然后:

if (chain.isEmpty()) {
   // We can skip creating a MethodInvocation: just invoke the target directly
   // Note that the final invoker must be an InvokerInterceptor so we know it does
   // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
   Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
   retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
   // We need to create a method invocation...
   invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
   // Proceed to the joinpoint through the interceptor chain.
   retVal = invocation.proceed();
}

這里就是判斷攔截器鏈有沒(méi)有東西,如果是空的就直接通過(guò)反射調(diào)用,不是空就進(jìn)行else邏輯了,那else是重點(diǎn)了,即invocation.proceed();

3.invocation.proceed()

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   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;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

第一個(gè)if是遞歸的終止條件,明顯是根據(jù)下標(biāo)進(jìn)行終止的條件

后面進(jìn)行前++,又調(diào)用了

((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

然而這里面是:

public Object invoke(MethodInvocation mi) throws Throwable {
   MethodInvocation oldInvocation = invocation.get();
   invocation.set(mi);
   try {
      return mi.proceed();
   }
   finally {
      invocation.set(oldInvocation);
   }
}

又跑回proceed方法去了,遞歸。

第二次來(lái)到的時(shí)候下標(biāo)就是0了(第一次是-1,默認(rèn)的),前++為1的下標(biāo)的話,取出來(lái)的東西繼續(xù)調(diào)用invoke發(fā)現(xiàn)進(jìn)的是AspectJAfterThrowingAdvice的invoke了(第一次是ExposeInvocationInterceptor的invoke,記錄下MethodInvocation供后面執(zhí)行鏈獲?。?/p>

這個(gè)AspectJAfterThrowingAdvice的invoke的源碼如下(不一樣):

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

繼續(xù)遞歸,不過(guò)這次把調(diào)用鏈try起來(lái)了,出異常就走異常增強(qiáng)通知invokeAdviceMethod

繼續(xù)debug,又是遞歸到invoke,但這次是AfterReturningAdviceInterceptor的:

public Object invoke(MethodInvocation mi) throws Throwable {
   Object retVal = mi.proceed();
   this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
   return retVal;
}

提一下啊,遞歸是棧結(jié)構(gòu)!所以我們先看到了異常調(diào)用代碼和返回通知代碼!

繼續(xù)遞歸proceed到了后置通知AspectJAfterAdvice類的invoke:

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

看到?jīng)],后置通知類的invokeAdviceMethod調(diào)用是用的finally,所以后置通知始終執(zhí)行!

繼續(xù)遞歸

跳到了前置通知類MethodBeforeAdviceInterceptor的invoke

public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   return mi.proceed();
}

注意這里不一樣了!它是先調(diào)用自己再調(diào)執(zhí)行鏈,這也就是為什么前置通知早于方法執(zhí)行

before方法執(zhí)行完之后,進(jìn)proceed了,遞歸即將結(jié)束:

image

所有的增強(qiáng)器取出來(lái)了,并執(zhí)行了before 這里遞歸就結(jié)束了,調(diào)用目標(biāo)方法:invokeJoinpoint

然后是后置通知各種,有異常就走之前try finally那里。

至此aop具體邏輯結(jié)束!

總結(jié)下易翻車點(diǎn):

1.注意看自己的源碼是哪個(gè)類,不然很懵逼,因?yàn)檎{(diào)了很多個(gè)類的同名方法invoke。

2.注意看是遞歸,和遞歸結(jié)束條件

3.注意invoke的實(shí)現(xiàn),對(duì)于不同的增強(qiáng)器的邏輯是不一樣的

4.增強(qiáng)器那個(gè)集合是有順序好的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容