【Spring源碼】20.AOP之切面的收集

image

1. 前言

我們知道aop實現(xiàn)的原理肯定是基于jdk動態(tài)代理和cglib代理,經過生成代理對象,對命中切面的方法進行增強。并將代理對象存放到ioc容器中,在其他對象需要的時候注入進去, 那么肯定 需要通過解析類 去解析 并收集 Advisor對象集合 : 需要增強的目標PointCut 以及 具體增強的邏輯Advice。 如果這個類是可以找到增強對象的,那么就應該生成代理。

2. 問題

2.1 生成的代理對象需要什么?

首先 需要進行 切面的收集和匹配

然后 把匹配到的切面 放入 生成的代理對象里,以便后續(xù)調用代理方法 來 決定調用哪個切面 來增強。

我們來看下wrapIfNecessary方法里是如何 進行切面的收集和匹配的。

image

3. Advisor增強對象的收集和匹配

3.1 Advisor增強對象的收集

該方法會先收集適合所有的Advisor增強對象,并過濾出匹配當前bean的Advisor對象

image

getAdvicesAndAdvisorsForBean

image

收集及匹配全在這

image

先看收集所有的切面findCandidateAdvisors()

這個方法是被他的子類重寫并調用的,看子類AnnotationAwareAspectJAutoProxyCreator的該方法

image
image

spring自帶的advisors可以不看,我們直接看我們自己寫的@Aspect類

image

這里有兩個緩存

image

buildAspectJAdvisors方法里會先判斷緩存

image

第一次沒有,肯定先解析再獲取,我們看解析的邏輯

可以看到會遍歷spring容器里的每一個beanName,然后根據(jù)beanName獲取class,如果類上有Aspect注解,說明是需要解析的

將 beanFactory, beanName 封裝成一個獲取Advisor的工廠,然后調用 this.advisorFactory.getAdvisors(factory) 去獲取advisors集合

image

3.1.1. 獲取沒有 @PointCut注解的方法集合

取出從獲取advisors工廠里取出beanClass, 去遍歷所有沒有@PointCut注解的方法,包含什么注解也沒有的方法

image

具體怎么獲取,也很簡單,遍歷每一個方法,如果沒有@Pointcut 注解就可以

image

3.1.2. 對要解析的方法集合排序

隨后會對 沒有@PointCut注解的方法集合進行排序, 按照這個順序排序 : Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

image

METHOD_COMPARATOR 比較器 :

image

3.1.3. 遍歷沒有@PointCut注解的方法的集合,開始創(chuàng)建Advisor對象

這里就開始要根據(jù)方法上面 aop相關的注解 來常見Advisor對象。

首先需要明確一點,Advisor定義的 是 增強的目標 與 增強的邏輯,

  1. 增強的目標 則是Pointcut對象定義的
  2. 增強的邏輯 則是Advice對象定義的

所以,Advisor 必須要包含Pointcut對象和 Advice對象。

image

3.1.3.1. Pointcut接口介紹

基于表達式的PointCut實現(xiàn)類是 AspectJExpressionPointcut類,它除了多持有一個表達式外,還會實現(xiàn)的 Pointcut接口。

 public interface Pointcut {

   ClassFilter getClassFilter();

   MethodMatcher getMethodMatcher();

   Pointcut TRUE = TruePointcut.INSTANCE;
}

需要重寫getClassFilter()來提供ClassFilter, ClassFilter是一個接口,重寫matches方法,來定義是否與類匹配

@FunctionalInterface
public interface ClassFilter {
        // 定義是否與類匹配
   boolean matches(Class<?> clazz);

   ClassFilter TRUE = TrueClassFilter.INSTANCE;
}

重寫 getMethodMatcher()方法 來提供MethodMatcher 對象, MethodMatcher也是一個接口

public interface MethodMatcher {
  // 定義是否與類匹配
   boolean matches(Method method, Class<?> targetClass);

   boolean isRuntime();
     // 定義是否與方法匹配
   boolean matches(Method method, Class<?> targetClass, Object... args);

   MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}

這里AspectJExpressionPointcut類,自己實現(xiàn)了ClassFilter接口,和IntroductionAwareMethodMatcher接口,可以看到實現(xiàn)至Pointcut接口接口的兩個方法 返回的都是自身。

image

重寫自ClassFilter接口,和IntroductionAwareMethodMatcher接口 對應的matches方法。
image

這里先這樣,后面匹配的時候 再看這兩個方法里具體的匹配邏輯。

3.1.3.2. PointCut對象的創(chuàng)建

進入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法

image

進入 getPointcut方法,這里先獲取Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這幾個注解,匹配到就返回

不可能獲取到@Pointcut注解
其實這里是不可能獲取到 @Pointcut ,因為前面 遍歷的整個方法的集合 就已經是排除掉了 @Pointcut注解的方法

獲取需要遍歷的整個方法集合代碼                 ![image](https://upload-images.jianshu.io/upload_images/23353704-e4ef94bec8d68a4a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

getPointcut方法

注解獲取到Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解里的其中任意一個,獲取注解里的pointcutExpression屬性,以及目標類的class對象,設置到創(chuàng)建的AspectJExpressionPointcut對象里,并返回

image

到這里pointCut對象已經創(chuàng)建完成,其實并不會去 掃描有@PointCut注解的方法,只是通過Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class里的pointcut屬性,去指向@PointCut注解的方法,到時候可以 根據(jù)這個 去找 @PointCut注解的方法,再去找@PointCut里面具體配置的表達式,明確切點。

3.1.3.3. Advice對象的創(chuàng)建

代碼回到入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) 方法。

會new出InstantiationModelAwarePointcutAdvisorImpl對象, 傳入AspectJExpressionPointcut對象到構造方法里

image

InstantiationModelAwarePointcutAdvisorImpl構造方法

會先存PointCut對象以及原生Method對象,再在instantiateAdvice方法里創(chuàng)建Advice對象

image

instantiateAdvice方法里創(chuàng)建Advice對象

image

首先從原生method方法,取出 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 這五個注解中的一個(一個方法只能取到其中一個注解,一般只會配一個)

image

再判斷注解,根據(jù)注解的不同,創(chuàng)建的Advice對象也不同

image

可以看到注解與創(chuàng)建的AspectJAroundAdvice類有如下對應關系

注解 Aavice實現(xiàn)類
@Around AspectJAroundAdvice
@Before AspectJMethodBeforeAdvice
@After AspectJAfterAdvice
@AfterReturning AspectJAfterReturningAdvice
@AfterThrowing AspectJAfterThrowingAdvice
MethodInterceptor接口

其中AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice這三個類是實現(xiàn)MethodInterceptor接口的

實現(xiàn)的invoke方法 持有 整個aop切面調用鏈上下文對象,以完成 切面調用鏈的回調,繼續(xù)調用剩下的的 切面。

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
   Object invoke(MethodInvocation invocation) throws Throwable;
}
public class AspectJAfterAdvice extends AbstractAspectJAdvice
      implements MethodInterceptor, AfterAdvice, Serializable {
   @Override
   public Object invoke(MethodInvocation mi) throws Throwable {
      try {
         return mi.proceed();
      }
      finally {
         invokeAdviceMethod(getJoinPointMatch(), null, null);
      }
   }
}
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
    public Object invoke(){
    // 繼承的父類 AbstractAspectJAdvice的invoke
    }
    @Override
    public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
        invokeAdviceMethod(getJoinPointMatch(), null, null);
    }
}

public class AspectJAfterAdvice extends AbstractAspectJAdvice
        implements MethodInterceptor, AfterAdvice, Serializable {
    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
}

而AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice這兩個切面沒有,到時候aop調用的時候,會對這兩個切面類進行 MethodInterceptor類型適配,以保證 調用和調用鏈 傳遞邏輯的 統(tǒng)一。

最終返回 各自的切面對象。

image

Advisor對象創(chuàng)建完成,存入緩存

直到所有方法都掃描完成,對應的Advisor對象 也創(chuàng)建成功,都存入緩存: beanName -> 對應類解析出來的 advisors

image

至此, 當容器內所有的beanName都遍歷完成,對應的class 通過解析、創(chuàng)建出來的Advisor對象全部 收集完畢。

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容