前言
往期文章:
在上一章向您生動(dòng)地講解Spring AOP 源碼(1)中,作者介紹了【開(kāi)啟AOP自動(dòng)代理的玄機(jī)】和【自動(dòng)代理的觸發(fā)時(shí)機(jī)】。
在本章中,作者會(huì)向您介紹,Spring AOP 是如何解析我們配置的Aspect,生成 Advisors 鏈的?
閑話不多說(shuō),讓我們直接開(kāi)始。
獲取對(duì)應(yīng) Bean 適配的Advisors 鏈
獲取對(duì)應(yīng) Bean 適配的 Advisors 鏈,分為兩步。
- 獲取容器所有的 advisors 作為候選,即解析Spring 容器中所有 Aspect 類(lèi)中的 advice 方法,包裝成 advisor;
- 從候選的 Advisors 中篩選出適配當(dāng)前 Bean的 Advisors 鏈;
未免讀者閱讀不連貫,我們重新貼一下上篇文章中我們最后講解的一段源碼,由此繼續(xù)往下講述。
源碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)

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

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

可以看到兩個(gè)方法都調(diào)用了findCandidateAdvisors()方法,也就是去獲取候選的 Advisors,我們進(jìn)去看看里面干了什么。
1. 獲取候選的 Advisors



從Debug 出來(lái)的線程??梢钥闯觯?code>AnnotationAwareAspectJAutoProxyCreator 通過(guò) 持有 BeanFactoryAspectJAdvisorsBuilder對(duì)象,來(lái)獲取Advisor鏈。
再往下看。源碼位置:BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
內(nèi)容較長(zhǎng),請(qǐng)大家跟著注釋耐心看下去。

這個(gè)方法除了等下要講 advisorFactory.getAdvisors(..)以外,需要注意的就是其為了避免每次都去獲取所有的beanName,解析判斷,引入了緩存的機(jī)制;還有就是Aspect類(lèi)是根據(jù)Spring Bean 是否被 @Aspect注解修飾來(lái)判斷的。
我們接下去看,真正的去獲取我們的Advisor的方法,this.advisorFactory.getAdvisors(factory) 方法如下:
源碼位置:ReflectiveAspectJAdvisorFactory#getAdvisors(..)

解析advice 方法成 advisor對(duì)象,
源碼位置:ReflectiveAspectJAdvisorFactory#getAdvisor(..)

生成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 的對(duì)象類(lèi)型是InstantiationModelAwarePointcutAdvisorImpl,我們來(lái)看下生成advisor時(shí)調(diào)用的這個(gè)類(lèi)的構(gòu)造函數(shù),

里面包括了一個(gè)重要的方法instantiateAdvice,即創(chuàng)建Advice,這也是我要強(qiáng)調(diào)的重點(diǎn),怎么解析出來(lái)一個(gè)advice。
源碼位置:InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice(..)

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

第一次解析Advisor的時(shí)機(jī)
關(guān)于第一次解析Advisor的時(shí)機(jī),我剛開(kāi)始也搞混了。所以在這里說(shuō)明一下。
這個(gè)圖是之前貼過(guò)的,第一次觸發(fā)的截圖。
AnnotationAwareAspectJAutoProxyCreator繼承了AbstractAutoProxyCreator實(shí)現(xiàn)了InstantiationAwareBeanPostProcessor接口:

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

2. 篩選 出 適配當(dāng)前類(lèi)的 Advisors
這里來(lái)一條分割線,至此,findCandidateAdvisors()算是解析完畢了。
但是我們通過(guò)這個(gè)方法只是獲得了所有候選的advisors,還記得我們這一節(jié)的標(biāo)題不?
【獲取對(duì)應(yīng) Bean 適配的Advisors 鏈】
那么我們下一步就是要過(guò)濾出適配當(dāng)前這個(gè) target class 的 advisors。

也就是上圖的findAdvisorsThatCanApply(..)
Search the given candidate Advisors to find all Advisors that can apply to the specified bean.
從給出的候選 Advisors 找出可以作用在 當(dāng)前bean 的 Advisors 鏈
Debug階段,篩選之前的候選 advisors 和篩選之后的可用的 advisors,

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

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

我們接下去看篩選的關(guān)鍵方法``AopUtils#canApply(..)`


篩選的工作主要由 ClassFilter 和 MethodMatcher 完成,比如AspectJExpressionPointcut的實(shí)現(xiàn)了ClassFilter和MethodMatcher接口,最終由AspectJ表達(dá)式解析,這個(gè)地方就復(fù)雜了,也不是核心點(diǎn)。
又是一條分割線。
到這里之后,Advisor的篩選過(guò)程我們算是講完了。

經(jīng)過(guò)排序之后,我們算是拿到了這個(gè)目標(biāo)類(lèi)使用的 Advisors 鏈。
小結(jié)
到這里,大家可以回顧一下,我們總算是把TODO-1【Spring AOP 如何 獲取對(duì)應(yīng) Bean 適配的Advisors 鏈】介紹完畢了,總結(jié)一下核心邏輯就是:
- 獲取當(dāng)前 IoC 容器中所有的 Aspect 類(lèi)
- 給 每個(gè)Aspect 類(lèi)的advice 方法創(chuàng)建一個(gè) Spring Advisor,這一步又能細(xì)分為
- 遍歷所有advice 方法
- 解析方法的注解和pointcut
- 實(shí)例化 Advisor 對(duì)象
- 獲取到 候選的 Advisors,并且緩存起來(lái),方便下一次直接獲取
- 從候選的 Advisors 中篩選出與目標(biāo)類(lèi) 適配的Advisor
- 獲取到 Advisor 的 切入點(diǎn) pointcut
- 獲取到 當(dāng)前 target 類(lèi) 所有的 public 方法
- 遍歷方法,通過(guò) 切入點(diǎn) 的 methodMatcher 匹配當(dāng)前方法,只有有一個(gè)匹配成功就相當(dāng)于當(dāng)前的Advisor 適配
- 對(duì)篩選之后的 Advisor 鏈進(jìn)行排序
- 結(jié)束
下一節(jié)中,我們會(huì)介紹 【代理類(lèi)的創(chuàng)建過(guò)程】,我們下次再會(huì)。