spring-AOP(一) 手動(dòng)代理

spring-AOP(一) 手動(dòng)代理

spring的設(shè)計(jì)原理是構(gòu)造一個(gè)個(gè)原子功能,然后不斷的通過設(shè)計(jì)模式在外圍進(jìn)行包裝、組合調(diào)用,最后實(shí)現(xiàn)復(fù)雜的邏輯功能。

知識(shí)導(dǎo)讀

  • 了解Aop聯(lián)盟定義的幾個(gè)概念,連接點(diǎn)、通知、攔截、切點(diǎn)、增強(qiáng)
  • ProxyFactory 定義了創(chuàng)建代理對(duì)象的工廠方法,不過該類主要用于提供代理配置
  • AopProxy 定義創(chuàng)建代理對(duì)象的接口,實(shí)現(xiàn)類有 jdk代理 和 cglib代理
  • 代理的本質(zhì)就是對(duì)目標(biāo)方法執(zhí)行的攔截增強(qiáng)
  • 創(chuàng)建代理最主要是提供 被代理對(duì)象 和 增強(qiáng)列表 AdvisorList
  • Advisor封裝了通知和切點(diǎn),實(shí)質(zhì)就是封裝了一個(gè)可以決定在什么類的什么方法上進(jìn)行增強(qiáng)的通知
  • 代理的最終目的就是在方法的執(zhí)行前后添加邏輯,最終構(gòu)建 ReflectiveMethodInvocation,創(chuàng)建代理類的目的就是為了實(shí)現(xiàn)選擇性的對(duì)目標(biāo)對(duì)象方法的攔截,然后將方法調(diào)用封裝為ReflectiveMethodInvocation
  • Pointcut提供了怎么篩選攔截哪些對(duì)象的哪些方法
  • 切面是通知的載體,通知是個(gè)方法,切面就是定義這些方法的對(duì)象。攔截器將這些通知按照順序串成一個(gè)鏈

AOP聯(lián)盟和Spring擴(kuò)展

AOP的實(shí)質(zhì)對(duì)連接點(diǎn)的增強(qiáng),一般通俗點(diǎn)講是對(duì)對(duì)方法執(zhí)行攔截增強(qiáng)
AOP聯(lián)盟定義了AOP的規(guī)范接口,聲明了兩個(gè)最基礎(chǔ)的接口,連接點(diǎn) 和 增強(qiáng) 。

連接點(diǎn) Joinpoint

public interface Joinpoint {
     //連接點(diǎn)的執(zhí)行
   Object proceed() throws Throwable;
  //一般用于返回被代理對(duì)象
   Object getThis();
  //一般用于返回目標(biāo)方法的Method對(duì)象
   AccessibleObject getStaticPart();
}
fZwewP

Joinpoint(連接點(diǎn)) 代表一個(gè)對(duì)象可以切入的地方,一般來說就是一個(gè)方法的執(zhí)行,MehtodInvocation將方法的調(diào)用過程進(jìn)行了封裝。spring實(shí)現(xiàn)擴(kuò)展了MethodInvocation,在ReflectiveMethodInvocation中既實(shí)現(xiàn)了方法調(diào)用的封裝,又定義了攔截器鏈,用于在方法執(zhí)行過程中進(jìn)行攔截增強(qiáng)。

通知 Advice

public interface Advice {

}

AOP聯(lián)盟聲明了通知的接口,用于標(biāo)記通知類型,最主要的接口實(shí)現(xiàn)是攔截器Interceptor

public interface Interceptor extends Advice {

}
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
  //定義了對(duì) 方法調(diào)用 進(jìn)行攔截的接口
   Object invoke(MethodInvocation invocation) throws Throwable;
}

在MethodInterceptor接口中聲明了invoke方法,需要一個(gè)MethodInvocation對(duì)象參數(shù)。用于對(duì)方法調(diào)用進(jìn)行攔截,然后執(zhí)行增強(qiáng)邏輯,在合適的時(shí)機(jī)回調(diào)MethodInvocation,實(shí)現(xiàn)增強(qiáng)的功能

spring對(duì)MethodInterceptor接口進(jìn)行了具體實(shí)現(xiàn),例如提供了前置通知、后置通知、最終通知、異常通知、環(huán)繞通知的實(shí)現(xiàn)類。

BfRb68
d9juQF

切點(diǎn) Pointcut

Pointcut是spring定義的一個(gè)接口,用于過濾目標(biāo)類和匹配目標(biāo)方法(連接點(diǎn))

public interface Pointcut {
   //用于過濾目標(biāo)類
   ClassFilter getClassFilter();
   //用于匹配目標(biāo)方法
   MethodMatcher getMethodMatcher();
  
   Pointcut TRUE = TruePointcut.INSTANCE;
}

Pointcut 的具體實(shí)現(xiàn),spring中Pointcut是很重的一塊邏輯,可以單獨(dú)出一篇文檔

NscLC2

增強(qiáng) Advisor

spring中定義的增強(qiáng)類,用于封裝一個(gè)Pointcut和一個(gè)Advice,實(shí)質(zhì)就是封裝了一個(gè)可以決定在什么類的什么方法上應(yīng)用的通知

public interface Advisor {
   Advice EMPTY_ADVICE = new Advice() {};
   //封裝的通知
   Advice getAdvice();
   boolean isPerInstance();
}
public interface PointcutAdvisor extends Advisor {
   //切點(diǎn),用于匹配連接點(diǎn),是否應(yīng)用Advice通知
   Pointcut getPointcut();
}
bgWnaP

工廠方式創(chuàng)建代理對(duì)象

ProxyFactory

通過ProxyFactory創(chuàng)建代理對(duì)象,需要配置以下信息

  1. 被代理對(duì)象
  2. 增強(qiáng)Advisor列表
  3. 被代理接口(非必須)
  4. 其他一些非必須配置(非必須)

下圖是ProxyFactory的繼承關(guān)系圖,通過看各個(gè)層級(jí)的字段,可以看出ProxyFactory主要定義的是一些創(chuàng)建代理的配置信息。

dXcJii

AopProxy

已知的可以創(chuàng)建代理對(duì)象的方式

  1. 使用jdk Proxy,需要?jiǎng)?chuàng)建一個(gè)InvocationHandler的實(shí)現(xiàn)類,調(diào)用代理對(duì)象的方法都會(huì)去調(diào)用InvocationHandler的實(shí)現(xiàn)類的invoke方法,所有的攔截和增強(qiáng)在invoke方法中做
  2. 使用cglib的Enhancer,需要?jiǎng)?chuàng)建一批MethodInterceptor的實(shí)現(xiàn)類,調(diào)用代理對(duì)象所有方法都會(huì)去調(diào)用MethodInterceptor實(shí)現(xiàn)類的intercept方法,所有的攔截和增強(qiáng)都在intercept方法中做

spring中定義了一個(gè)AopProxy接口,用于獲取代理類,實(shí)現(xiàn)類是JdkProxy和cglibProxy,ProxyFactory提供了創(chuàng)建AopProxy的配置信息,創(chuàng)建代理類對(duì)象的工作交由AopProxy的實(shí)現(xiàn)類實(shí)現(xiàn)。

X2TMay

通過ProxyFactory配置創(chuàng)建AopProxy實(shí)現(xiàn)

spring中定義了ProxyFactory用于創(chuàng)建代理對(duì)象,下面是創(chuàng)建代理對(duì)象的一個(gè)demo。

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTargetSource(targetSource);//設(shè)置被代理對(duì)象
factory.setInterfaces(IUserService.class);//設(shè)置要代理的接口
proxyFactory.setProxyTargetClass(true);//設(shè)置使用cglib創(chuàng)建代理
proxyFactory.setExposeProxy(true);//設(shè)置是否暴露代理類
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);//設(shè)置目標(biāo)類的增強(qiáng) Advisor列表
return proxyFactory.getProxy(getProxyClassLoader());//創(chuàng)建代理類對(duì)象

調(diào)用ProxyFactory的getProxy創(chuàng)建代理類對(duì)象,首先會(huì)創(chuàng)建一個(gè)AopProxy對(duì)象,然后調(diào)用AopProxy的getProxy方法獲取代理類對(duì)象,在整個(gè)創(chuàng)建代理類過程中,ProxyFactory用于提供配置

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

調(diào)用父類ProxyCreatorSupport中的createAopProxy創(chuàng)建AopProxy。

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}

在AopProxyFactory的createAopProxy創(chuàng)建了AopProxy的具體實(shí)現(xiàn),會(huì)通過ProxyFactory中提供的配置來選擇使用jdk代理還是cglib代理

注意,cglib也可以創(chuàng)建基于接口的代理

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
      Class<?> targetClass = config.getTargetClass();
      if (targetClass == null) {
         throw new AopConfigException("TargetSource cannot determine target class: " +
               "Either an interface or a target is required for proxy creation.");
      }
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
      }
      return new ObjenesisCglibAopProxy(config);
   }
   else {
      return new JdkDynamicAopProxy(config);
   }
}

通過AopProxy創(chuàng)建代理類對(duì)象

創(chuàng)建完AopProxy之后,調(diào)用AopProxy實(shí)現(xiàn)類的getProxy就可以創(chuàng)建代理類,和代理類對(duì)象。

jdk代理

首先來分析spring是如何實(shí)現(xiàn)jdk代理的,在JdkDynamicAopProxy中g(shù)etProxy中通過調(diào)用Proxy的api創(chuàng)建代理類對(duì)象

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
  //獲取ProxyFactory提供的配置,接口
  Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  //調(diào)用Proxy的api創(chuàng)建代理類對(duì)象。
  return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

由于JdkDynamicAopProxy自己本身實(shí)現(xiàn)了InvocationHandler接口,所以在創(chuàng)建代理對(duì)象的時(shí)候傳遞的是this

cglib代理

jdk代理比較簡單,接下來看下CglibAopProxy是如何通過cglib來創(chuàng)建代理類對(duì)象的

@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
   try {
      //獲取ProxyFactory配置的目標(biāo)類型
      Class<?> rootClass = this.advised.getTargetClass();
      Class<?> proxySuperClass = rootClass;
      //如果當(dāng)前的類型已經(jīng)是cglib創(chuàng)建的代理類,使用代理類的父類
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            this.advised.addInterface(additionalInterface);
         }
      }
      //檢查下方法是否是final修飾和 private
      validateClassIfNecessary(proxySuperClass, classLoader);
     //使用cglib的Enhancer創(chuàng)建代理
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);//設(shè)置父類
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
      //最重要的一步,組裝cglib需要的攔截器實(shí)現(xiàn)
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      //設(shè)置攔截器過濾器,用于指定什么方法應(yīng)用什么攔截器
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);
      // enhancer創(chuàng)建代理
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException | IllegalArgumentException ex) {
     //此處省略代碼....
   }
   catch (Throwable ex) {
      //此處省略代碼....
   }
}

通過以上邏輯,spring就完成了代理類的創(chuàng)建,接下來對(duì)代理類的方法調(diào)用都會(huì)去調(diào)用InvocationHandler的invoke方法或者Callback的intercept方法。

代理類的方法調(diào)用

jdk代理的方法調(diào)用

zsq7Kv

JdkDynamicAopProxy實(shí)現(xiàn)了InvocationHandler的invoke方法,代理類對(duì)象所有方法的執(zhí)行都會(huì)通過invoke方法來調(diào)用

  1. 根據(jù)Pointcut篩選應(yīng)用目標(biāo)方法的Advisor,將Advisor中的Advice封裝為增強(qiáng)目標(biāo)方法的攔截器鏈

  2. 基于攔截器鏈封裝MethodInvocation實(shí)現(xiàn)類對(duì)象,方法的調(diào)用和攔截增強(qiáng)全由MethodInvocation實(shí)現(xiàn),

注意每次目標(biāo)方法執(zhí)行都會(huì)新建一個(gè)MethodInvocation對(duì)象

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   //用于記錄ThreadLocal中之前的代理類對(duì)象
   Object oldProxy = null;
   boolean setProxyContext = false;
   //被代理對(duì)象
   TargetSource targetSource = this.advised.targetSource;
   Object target = null;
   try {
     //此處省略代碼....
      Object retVal;
          //判斷如果要暴露代理類對(duì)象,如果是將代理對(duì)象放入ThreadLocal,通過AopContext.currentProxy獲取
     //同時(shí)要記錄下 ThreadLocal中之前存儲(chǔ)的代理類對(duì)象,方法執(zhí)行完畢后要重置回去
      if (this.advised.exposeProxy) {
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);
      //最重要的一步 封裝獲取攔截器鏈
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      //如果攔截器鏈為空,直接反射調(diào)用被代理對(duì)象的方法
      if (chain.isEmpty()) {
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }else {
         //如果存在攔截器鏈,構(gòu)造方法調(diào)用的封裝對(duì)象MethodInvocation,被代理對(duì)象方法的調(diào)用以及攔截器的增強(qiáng)封裝都通過該類實(shí)現(xiàn),每次都新建ReflectiveMethodInvocation對(duì)象,這個(gè)對(duì)象中有currentInterceptorIndex,避免污染
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         retVal = invocation.proceed();
      }
      //此處省略代碼....
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // 方法執(zhí)行完畢后重置ThreadLocal中的代理類對(duì)象
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

來看下spring中是如何篩選目標(biāo)方法的攔截器鏈的,在getInterceptorsAndDynamicInterceptionAdvice會(huì)首先去獲取緩存中的攔截器鏈,如果沒有,再進(jìn)行篩選解析,感覺這里還是直接new一個(gè)list,然后將cached放進(jìn)去,避免后續(xù)流程修改列表

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
  //使用方法名作為緩存key,將攔截器鏈緩存起來,避免重復(fù)解析
   MethodCacheKey cacheKey = new MethodCacheKey(method);
   List<Object> cached = this.methodCache.get(cacheKey);
   if (cached == null) {
      cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
      this.methodCache.put(cacheKey, cached);
   }
   return cached;
}

通過DefaultAdvisorChainFactory構(gòu)建攔截器鏈,主要就是通過Advisor中的Pointcut的ClassFilter和MethodMatcher來篩選能夠增強(qiáng)目標(biāo)方法的Advisor,然后封裝為攔截器MethodInterceptor對(duì)象,組裝成攔截器鏈返回

@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class<?> targetClass) {
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
   Advisor[] advisors = config.getAdvisors();//獲取配置中的Advisor列表
   List<Object> interceptorList = new ArrayList<>(advisors.length);
   Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;
    //遍歷Advisor,篩選能夠增強(qiáng)目標(biāo)方法的Advisor,并封裝為攔截器鏈返回
   for (Advisor advisor : advisors) {
     //如果是PointcutAdvisor,判斷Advisor的Pointcut是否攔截本方法
      if (advisor instanceof PointcutAdvisor) {
         PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
        //先通過ClassFilter判斷是否攔截目標(biāo)類
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            boolean match;
           //再通過MethodMatcher判斷是否攔截目標(biāo)方法
            if (mm instanceof IntroductionAwareMethodMatcher) {
               if (hasIntroductions == null) {
                  hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
               }
               match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
            }
            else {
               match = mm.matches(method, actualClass);
            }
            if (match) {
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
              //如果是要根據(jù)運(yùn)行時(shí)參數(shù)進(jìn)行方法校驗(yàn),需要封裝攔截器,將methodMatcher傳下去,用于執(zhí)行時(shí)判斷參數(shù)
               if (mm.isRuntime()) {
                  for (MethodInterceptor interceptor : interceptors) {
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  }
               }else {
                  interceptorList.addAll(Arrays.asList(interceptors));
               }
            }
         }
      }//引介增強(qiáng),作用范圍是類,只需判斷是否攔截目標(biāo)類就行
      else if (advisor instanceof IntroductionAdvisor) {
         IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         }
      }else {//其他類型Advisor,不需要過濾,默認(rèn)攔截所有方法
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      }
   }
   return interceptorList;
}

獲取到目標(biāo)方法的攔截器鏈之后,接下來構(gòu)建MethodInvocation對(duì)象,調(diào)用MethodInvocation的proceed方法。在MethodInvocation中會(huì)在目標(biāo)方法執(zhí)行前后執(zhí)行攔截器鏈中的增強(qiáng)方法,然后在合適的時(shí)機(jī)再回調(diào)目標(biāo)方法,實(shí)現(xiàn)代理的邏輯。

通過ReflectiveMethodInvocation的構(gòu)造器可以看出,該對(duì)象就是對(duì)目標(biāo)方法調(diào)用和攔截器鏈的封裝

//構(gòu)造器
protected ReflectiveMethodInvocation(
            Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments,
            @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;//代理類對(duì)象
        this.target = target;//被代理對(duì)象
        this.targetClass = targetClass;//被代理對(duì)象類型
        this.method = BridgeMethodResolver.findBridgedMethod(method);//目標(biāo)方法
        this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//方法參數(shù)
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//攔截器鏈
}

再來看如何在proceed方法完成對(duì)方法的增強(qiáng),在該方法中會(huì)遍歷執(zhí)行攔截器鏈中的攔截方法,所有攔截器都執(zhí)行完畢后再調(diào)用被代理類的目標(biāo)方法。攔截器鏈?zhǔn)窃诖眍惖姆椒ㄖ袀魅氲模沂蔷彺孢^的共享對(duì)象,這里避免修改該鏈,使用currentInterceptorIndex來記錄鏈的執(zhí)行位置。其實(shí)這塊是可以進(jìn)行優(yōu)化的

private int currentInterceptorIndex = -1;//記錄攔截器鏈執(zhí)行第幾個(gè)攔截器

public Object proceed() throws Throwable {
   // 攔截器鏈遍歷完畢后,調(diào)用目標(biāo)方法
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
     //遍歷獲取下一個(gè)攔截器
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  //如果是動(dòng)態(tài)執(zhí)行過程中攔截,需要根據(jù)參數(shù)來判斷是否需要對(duì)目標(biāo)方法進(jìn)行攔截增強(qiáng)
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
     //通過參數(shù)判斷是否需要增強(qiáng),如果需要直接調(diào)用攔截器的invoke方法,并把當(dāng)前MethodInvocation傳遞過來,以便方法攔截邏輯執(zhí)行后再次調(diào)回來
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      } else {
        //如果不進(jìn)行攔截,遞歸,重新執(zhí)行下一個(gè)攔截器.
         return proceed();
      }
   } else {
     //靜態(tài)攔截器,直接調(diào)用攔截器對(duì)方法進(jìn)行增強(qiáng)
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

ReflectiveMethodInvocation中,在執(zhí)行完攔截器鏈中所有的攔截器邏輯之后,會(huì)調(diào)用被代理對(duì)象的目標(biāo)方法,默認(rèn)是通過反射調(diào)用

@Nullable
protected Object invokeJoinpoint() throws Throwable {
   return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

CglibMethodInvocation中覆寫了ReflectiveMethodInvocation的invokeJoinpoint方法,會(huì)通過cglib的MethodProxy進(jìn)行調(diào)用,避免反射

@Override
protected Object invokeJoinpoint() throws Throwable {
   if (this.methodProxy != null) {
      return this.methodProxy.invoke(this.target, this.arguments);
   } else {
      return super.invokeJoinpoint();
   }
}

分析到現(xiàn)在,AOP剩下的功能就是要看Spring中定義的幾種通知類型是如何在攔截器中進(jìn)行調(diào)用的。

攔截器中通知方法的執(zhí)行

spring中對(duì)通知advice和攔截器MethodInterceptor的繼承實(shí)現(xiàn)由點(diǎn)亂,不太明白為什么要這樣做,不如分開

在攔截器中可以方便的在目標(biāo)方法執(zhí)行前后添加邏輯,很簡單。在使用@Aspect的切面的時(shí)候,會(huì)調(diào)用@Aspect注冊(cè)的bean中的方法通知。這里重點(diǎn)看下@Aspect是如何實(shí)現(xiàn)的

前置通知

首先來看下前置通知攔截器中如何調(diào)用前置通知。在invoke方法中先調(diào)用通知,然后再回調(diào)MethodInvocation目標(biāo)方法

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
   //包裝了一個(gè)前置通知
   private final MethodBeforeAdvice advice;
   public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
      this.advice = advice;
   }
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      //調(diào)用前置通知方法
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());、
      //通知方法調(diào)用完畢之后,回調(diào) 連接點(diǎn)的方法執(zhí)行
      return mi.proceed();
   }

}

AspectJMethodBeforeAdvice實(shí)現(xiàn)了MethodBeforeAdvice

public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {

   public AspectJMethodBeforeAdvice(
         Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
      super(aspectJBeforeAdviceMethod, pointcut, aif);
   }

   @Override
   public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
     //調(diào)用 @aspect 切面中聲明的方法
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

在AbstractAspectJAdvice定義了切面方法調(diào)用過程

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
      @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {
   //獲取方法參數(shù),反射調(diào)用通知方法
   return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}

通知方法反射調(diào)用,完成前置通知的調(diào)用

protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
   Object[] actualArgs = args;
   if (this.aspectJAdviceMethod.getParameterCount() == 0) {
      actualArgs = null;
   }
   try {
      ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
      //通知方法反射調(diào)用,對(duì)象是@aspect注冊(cè)的bean
      return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
   }
   catch (IllegalArgumentException ex) {
      //...
   }
}

環(huán)繞通知

看完了前置通知,后置通知、異常通知基本都一樣,這里看下環(huán)繞通知,環(huán)繞通知實(shí)現(xiàn)比較復(fù)雜

環(huán)繞通知直接調(diào)用了通知方法,在這里沒有再回調(diào)目標(biāo)方法的執(zhí)行,因?yàn)榄h(huán)繞通知對(duì)目標(biāo)方法的執(zhí)行寫在通知方法內(nèi)部,接下來看環(huán)繞通知是如何完成既完成對(duì)目標(biāo)方法的調(diào)用又完成剩余通知的執(zhí)行

public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
       if (!(mi instanceof ProxyMethodInvocation)) {
        //...
       }
       ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
       ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
       JoinPointMatch jpm = getJoinPointMatch(pmi);
       //調(diào)用通知方法
       return invokeAdviceMethod(pjp, jpm, null, null);
    }
}

lazyGetProceedingJoinPoint返回了一個(gè)ProceedingJoinPoint,封裝了原始的MethodInvocation對(duì)象

protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
   return new MethodInvocationProceedingJoinPoint(rmi);
}

接下來通知方法的調(diào)用跟前置通知一樣,只不過是將ProceedingJoinPoint作為參數(shù)傳遞給了通知方法

@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) {
    System.out.println("around before");
    Object result = null;
    try {
        //調(diào)用原始方法
        result = p.proceed();
    } catch (Throwable e) {
    }
    System.out.println("around after");
    return result;
}

調(diào)用p.proceed() ,在 MethodInvocationProceedingJoinPoint 會(huì)將原始的 MethodInvocation克隆一份,會(huì)將剩余攔截器鏈和下標(biāo)復(fù)制下來,然后重新調(diào)用 proceed方法

@Override
public Object proceed() throws Throwable {
   return this.methodInvocation.invocableClone().proceed();
}

ReflectiveMethodInvocation進(jìn)行深克隆

@Override
public MethodInvocation invocableClone() {
   Object[] cloneArguments = this.arguments;
   if (this.arguments.length > 0) {
      // Build an independent copy of the arguments array.
      cloneArguments = new Object[this.arguments.length];
      System.arraycopy(this.arguments, 0, cloneArguments, 0, this.arguments.length);
   }
   return invocableClone(cloneArguments);
}
@Override
public MethodInvocation invocableClone(Object... arguments) {
   ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
   clone.arguments = arguments;
   return clone;
}
最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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