Spring AOP通知執(zhí)行原理

1. AOP的核心概念

  • 切面(Aspect):似于 Java 中的類聲明,常用于應(yīng)用中配置事務(wù)或者日志管理。一般使用 @Aspect 注解或者 <aop:aspect> 來(lái)定義一個(gè)切面。
  • 連接點(diǎn)(Join Point):程序執(zhí)行中的特定點(diǎn),比如方法執(zhí)行、處理一個(gè)異常等。
  • 切點(diǎn)(Pointcut):通過(guò)一種規(guī)則匹配的正則表達(dá)式,當(dāng)有連接點(diǎn)可以匹配到切點(diǎn)時(shí),就會(huì)觸發(fā)改切點(diǎn)相關(guān)聯(lián)的指定通知。
  • 通知(Advice):在切面中某個(gè)連接點(diǎn)采取的動(dòng)作,通知方式也有5種:
    • around(環(huán)繞通知):前后都加
    • before(前置通知)
    • after(后置通知)
    • exception(異常通知)
    • return(返回通知)
  • 織入(Weaving):鏈接切面和目標(biāo)對(duì)象創(chuàng)建一個(gè)通知對(duì)象的過(guò)程。

AOP其實(shí)就是一種編程思想,而這上面的這個(gè)點(diǎn)就是編程的具體實(shí)現(xiàn)規(guī)范。

一個(gè)應(yīng)用中可以有多種通知方式所以在AOP中引入一種設(shè)計(jì)模式責(zé)任鏈模式通過(guò)這這種模式來(lái)順序執(zhí)行每一個(gè)通知當(dāng)然也可以使用@Order注解,配置數(shù)字越小,越先執(zhí)行。

2. AOP的執(zhí)行過(guò)程

準(zhǔn)備demo

@Component
public class AopTest {

    public void log(){
        System.out.println("正常執(zhí)行方法。。。。。。。。。。。");
    }
}
@Component
@Aspect
public class AspectTest {

    @Pointcut("execution(*  com.test.*.service.AopTest.*(..))")
    public void pointLog(){

    }

    @Before("pointLog()")
    public void before(){
        System.out.println("執(zhí)行方法之前。。。。。。before");
    }

    @After("pointLog()")
    public void after(){
        System.out.println("執(zhí)行方法之后。。。。。。after");
    }

}

進(jìn)入到DynamicAdvisedInterceptor 這個(gè)靜態(tài)內(nèi)部類中的intercept方法。

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
        @Override
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            。。。
                // 從advised中 獲取配置好的AOP的通知方法
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                //如果沒有通知方法則調(diào)用target對(duì)象的方法,顯然chain不為空則走else邏輯
                if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {

                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    try {
                        retVal = methodProxy.invoke(target, argsToUse);
                    }
                    catch (CodeGenerationException ex) {
                        CglibMethodInvocation.logFastClassGenerationFailure(method);
                        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                    }
                }
                else {
                  //通過(guò)CglibMethodInvocation來(lái)啟動(dòng)advice通知,proceed()通過(guò)調(diào)用super.proceed();
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            。。。
        }
    }

進(jìn)入到ReflectiveMethodInvocation 中的proceed()方法

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
        。。。

 /**
  * Index from 0 of the current interceptor we're invoking.
  * -1 until we invoke: then the current interceptor.
  */
 private int currentInterceptorIndex = -1;

 // 省略其他的方法

 @Override
 @Nullable
 public Object proceed() throws Throwable {
    // 從索引為-1的攔截器開始調(diào)用,并且按順序遞增,如果整個(gè)List chain中調(diào)用完畢,則開始調(diào)用target的函數(shù)
    // 具體的實(shí)現(xiàn)方式在AOPUtils.invokeJoinpointUsingRefection方法中,其實(shí)就是通過(guò)反射實(shí)現(xiàn)目標(biāo)方法
  if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
   return invokeJoinpoint();
  }
  // 獲取下一個(gè)需要執(zhí)行的攔截器,沿著定義好的interceptorOrInterceptionAdvice的鏈進(jìn)行處理
  //在new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()時(shí),
  //已經(jīng)將通知方法傳入到interceptorsAndDynamicMethodMatchers中。
  Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // 對(duì)攔截器進(jìn)行動(dòng)態(tài)匹配,如果和定義的pointcut匹配 則就會(huì)執(zhí)行當(dāng)前的這個(gè)advice
   InterceptorAndDynamicMethodMatcher dm =
     (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
   Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
   if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
    return dm.interceptor.invoke(this);
   }
   else {
    return proceed();
   }
  }
  else {
  //普通攔截器,直接調(diào)用攔截器,將當(dāng)前的this(CglibMethodInvocation)作為參數(shù)保證當(dāng)前實(shí)例中調(diào)用鏈的執(zhí)行
    //這里就利用到了責(zé)任鏈模式,進(jìn)行循環(huán)調(diào)用,直到所有通知執(zhí)行完成
   return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  }
 }
}

Spring中的五種通知,首先是通過(guò)具Spring容器的啟動(dòng)過(guò)程獲取到具體的通知,在調(diào)用對(duì)象時(shí),通過(guò)動(dòng)態(tài)代理ASM技術(shù),把需要執(zhí)行的advice先全部放在一個(gè)chain對(duì)象的集合中,為了保證整個(gè)鏈的調(diào)用默認(rèn)會(huì)先調(diào)用ExposeInvocationInterceptor去觸發(fā)整個(gè)鏈?zhǔn)綀?zhí)行,在執(zhí)行完每一個(gè)advice時(shí)后都會(huì)再次回到super的proceed方法中,執(zhí)行下一個(gè)advice,在執(zhí)行不同的advice時(shí)有對(duì)應(yīng)的切面通知方法,當(dāng)所有的advice執(zhí)行完畢再通過(guò)cglib的FastClass機(jī)制調(diào)用目標(biāo)方法

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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