向您生動講解Spring AOP 源碼(2)

前言

往期文章:

在上一章向您生動地講解Spring AOP 源碼(1)中,作者介紹了【開啓AOP自動代理的玄機】和【自動代理的觸發時機】。

在本章中,作者會向您介紹,Spring AOP 是如何解析我們配置的Aspect,生成 Advisors 鏈的?

閒話不多說,讓我們直接開始。

獲取對應 Bean 適配的Advisors 鏈

獲取對應 Bean 適配的 Advisors 鏈,分爲兩步。

  1. 獲取容器所有的 advisors 作爲候選,即解析Spring 容器中所有 Aspect 類中的 advice 方法,包裝成 advisor;
  2. 從候選的 Advisors 中篩選出適配當前 Bean的 Advisors 鏈;

未免讀者閱讀不連貫,我們重新貼一下上篇文章中我們最後講解的一段源碼,由此繼續往下講述。

源碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)

wrapIfNecessary

源碼位置:AspectJAwareAdvisorAutoProxyCreator#shouldSkip(..)

shouldSkip.png

源碼位置:AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean(..)AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(..)

getAdvicesAndAdvisorsForBean.png

可以看到兩個方法都調用了findCandidateAdvisors()方法,也就是去獲取候選的 Advisors,我們進去看看裏面幹了什麼。

1. 獲取候選的 Advisors

findCandidateAdvisors.png

image.png

image.png

從Debug 出來的線程棧可以看出,AnnotationAwareAspectJAutoProxyCreator 通過 持有 BeanFactoryAspectJAdvisorsBuilder對象,來獲取Advisor鏈。

再往下看。源碼位置:BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

內容較長,請大家跟着註釋耐心看下去。

buildAspectJAdvisors1.png

這個方法除了等下要講 advisorFactory.getAdvisors(..)以外,需要注意的就是其爲了避免每次都去獲取所有的beanName,解析判斷,引入了緩存的機制;還有就是Aspect類是根據Spring Bean 是否被 @Aspect註解修飾來判斷的。

我們接下去看,真正的去獲取我們的Advisor的方法,this.advisorFactory.getAdvisors(factory) 方法如下:

源碼位置:ReflectiveAspectJAdvisorFactory#getAdvisors(..)

getAdvisors.png

解析advice 方法成 advisor對象,

源碼位置:ReflectiveAspectJAdvisorFactory#getAdvisor(..)

getAdvisor.png

生成advisor

如何生成advisor也值得一提。

註釋方式下,我們聲明的advice 方法是這樣的。(不熟悉範例的可以看上一篇文章)

@Aspect
@Component
public class PointCutConfig {
    // ... 省略
    // service 層
    @Pointcut("within(ric.study.demo.aop.svc..*)")
    public void inSvcLayer() {}
    // ... 省略
}
@Aspect
@Component
public class GlobalAopAdvice {

    @Before("ric.study.demo.aop.PointCutConfig.inSvcLayer()")
    public void logBeforeSvc(JoinPoint joinPoint) {
        System.out.println("在service 層前打印日誌");
        System.out.println("攔截的service 方法的方法簽名: " + joinPoint.getSignature());
    }
}

advice方法.png

生成之後是這樣的,

image.png

advice 的對象類型是InstantiationModelAwarePointcutAdvisorImpl,我們來看下生成advisor時調用的這個類的構造函數,

InstantiationModelAwarePointcutAdvisorImpl.png

裏面包括了一個重要的方法instantiateAdvice,即創建Advice,這也是我要強調的重點,怎麼解析出來一個advice。

源碼位置:InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice(..)

源碼位置:ReflectiveAspectJAdvisorFactory#getAdvice(..)

第一次解析Advisor的時機

關於第一次解析Advisor的時機,我剛開始也搞混了。所以在這裏說明一下。

這個圖是之前貼過的,第一次觸發的截圖。

AnnotationAwareAspectJAutoProxyCreator繼承了AbstractAutoProxyCreator實現了InstantiationAwareBeanPostProcessor接口:

image.png

會在生成target class 對象之前,調用 postProcessBeforeInstantiation(..),具體的代碼可以去看AbstractAutowireCapableBeanFactory#createBean(..)方法。我們這邊直接看一下 postProcessBeforeInstantiation(..)AbstractAutoProxyCreator中的實現。

postProcessBeforeInstantiation.png

2. 篩選 出 適配當前類的 Advisors

這裏來一條分割線,至此,findCandidateAdvisors()算是解析完畢了。

但是我們通過這個方法只是獲得了所有候選的advisors,還記得我們這一節的標題不?

【獲取對應 Bean 適配的Advisors 鏈】

那麼我們下一步就是要過濾出適配當前這個 target class 的 advisors。

findEligibleAdvisors.png

也就是上圖的findAdvisorsThatCanApply(..)

Search the given candidate Advisors to find all Advisors that can apply to the specified bean.

從給出的候選 Advisors 找出可以作用在 當前bean 的 Advisors 鏈

Debug階段,篩選之前的候選 advisors 和篩選之後的可用的 advisors,

image.png

源碼位置:AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply(..)

findAdvisorsThatCanApply.png

源碼位置:AopUtils#findAdvisorsThatCanApply(..)

我們接下去看篩選的關鍵方法``AopUtils#canApply(…)`

篩選的工作主要由 ClassFilter 和 MethodMatcher 完成,比如AspectJExpressionPointcut的實現了ClassFilter和MethodMatcher接口,最終由AspectJ表達式解析,這個地方就複雜了,也不是核心點。


又是一條分割線。

到這裏之後,Advisor的篩選過程我們算是講完了。

findEligibleAdvisors2.png

經過排序之後,我們算是拿到了這個目標類使用的 Advisors 鏈。

小結

到這裏,大家可以回顧一下,我們總算是把TODO-1【Spring AOP 如何 獲取對應 Bean 適配的Advisors 鏈】介紹完畢了,總結一下核心邏輯就是:

  1. 獲取當前 IoC 容器中所有的 Aspect 類
  2. 給 每個Aspect 類的advice 方法創建一個 Spring Advisor,這一步又能細分爲
    1. 遍歷所有advice 方法
    2. 解析方法的註解和pointcut
    3. 實例化 Advisor 對象
  3. 獲取到 候選的 Advisors,並且緩存起來,方便下一次直接獲取
  4. 從候選的 Advisors 中篩選出與目標類 適配的Advisor
    1. 獲取到 Advisor 的 切入點 pointcut
    2. 獲取到 當前 target 類 所有的 public 方法
    3. 遍歷方法,通過 切入點 的 methodMatcher 匹配當前方法,只有有一個匹配成功就相當於當前的Advisor 適配
  5. 對篩選之後的 Advisor 鏈進行排序
  6. 結束

下一節中,我們會介紹 【代理類的創建過程】,我們下次再會。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章