前言
往期文章:
在上一章向您生動地講解Spring AOP 源碼(1)中捏浊,作者介紹了【開啟AOP自動代理的玄機】和【自動代理的觸發(fā)時機】。
在本章中,作者會向您介紹溉跃,Spring AOP 是如何解析我們配置的Aspect撇吞,生成 Advisors 鏈的吸申?
閑話不多說胖齐,讓我們直接開始肠套。
獲取對應 Bean 適配的Advisors 鏈
獲取對應 Bean 適配的 Advisors 鏈根竿,分為兩步陵像。
- 獲取容器所有的 advisors 作為候選,即解析Spring 容器中所有 Aspect 類中的 advice 方法寇壳,包裝成 advisor醒颖;
- 從候選的 Advisors 中篩選出適配當前 Bean的 Advisors 鏈;
未免讀者閱讀不連貫壳炎,我們重新貼一下上篇文章中我們最后講解的一段源碼泞歉,由此繼續(xù)往下講述。
源碼位置:AbstractAutoProxyCreator#wrapIfNecessary(..)
源碼位置:AspectJAwareAdvisorAutoProxyCreator#shouldSkip(..)
源碼位置:AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean(..)
冕广、AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(..)
可以看到兩個方法都調用了findCandidateAdvisors()
方法疏日,也就是去獲取候選的 Advisors,我們進去看看里面干了什么撒汉。
1. 獲取候選的 Advisors
從Debug 出來的線程椆涤牛可以看出,AnnotationAwareAspectJAutoProxyCreator
通過 持有 BeanFactoryAspectJAdvisorsBuilder
對象睬辐,來獲取Advisor鏈挠阁。
再往下看。源碼位置:BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
內容較長溯饵,請大家跟著注釋耐心看下去侵俗。
這個方法除了等下要講 advisorFactory.getAdvisors(..)
以外,需要注意的就是其為了避免每次都去獲取所有的beanName丰刊,解析判斷隘谣,引入了緩存的機制;還有就是Aspect類是根據(jù)Spring Bean 是否被 @Aspect
注解修飾來判斷的。
我們接下去看寻歧,真正的去獲取我們的Advisor的方法掌栅,this.advisorFactory.getAdvisors(factory)
方法如下:
源碼位置:ReflectiveAspectJAdvisorFactory#getAdvisors(..)
解析advice 方法成 advisor對象,
源碼位置: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 的對象類型是InstantiationModelAwarePointcutAdvisorImpl
晌缘,我們來看下生成advisor時調用的這個類的構造函數(shù),
里面包括了一個重要的方法instantiateAdvice痢站,即創(chuàng)建Advice磷箕,這也是我要強調的重點,怎么解析出來一個advice瑟押。
源碼位置:InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice(..)
源碼位置:ReflectiveAspectJAdvisorFactory#getAdvice(..)
第一次解析Advisor的時機
關于第一次解析Advisor的時機搀捷,我剛開始也搞混了。所以在這里說明一下多望。
這個圖是之前貼過的,第一次觸發(fā)的截圖氢烘。
AnnotationAwareAspectJAutoProxyCreator
繼承了AbstractAutoProxyCreator
實現(xiàn)了InstantiationAwareBeanPostProcessor
接口:
會在生成target class 對象之前怀偷,調用 postProcessBeforeInstantiation(..)
,具體的代碼可以去看AbstractAutowireCapableBeanFactory#createBean(..)
方法播玖。我們這邊直接看一下 postProcessBeforeInstantiation(..)
在AbstractAutoProxyCreator
中的實現(xiàn)椎工。
2. 篩選 出 適配當前類的 Advisors
這里來一條分割線,至此蜀踏,findCandidateAdvisors()
算是解析完畢了维蒙。
但是我們通過這個方法只是獲得了所有候選的advisors,還記得我們這一節(jié)的標題不果覆?
【獲取對應 Bean 適配的Advisors 鏈】
那么我們下一步就是要過濾出適配當前這個 target class 的 advisors颅痊。
也就是上圖的findAdvisorsThatCanApply(..)
Search the given candidate Advisors to find all Advisors that can apply to the specified bean.
從給出的候選 Advisors 找出可以作用在 當前bean 的 Advisors 鏈
Debug階段,篩選之前的候選 advisors 和篩選之后的可用的 advisors局待,
源碼位置:AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply(..)
源碼位置:AopUtils#findAdvisorsThatCanApply(..)
我們接下去看篩選的關鍵方法``AopUtils#canApply(..)`
篩選的工作主要由 ClassFilter 和 MethodMatcher 完成斑响,比如AspectJExpressionPointcut的實現(xiàn)了ClassFilter和MethodMatcher接口,最終由AspectJ表達式解析钳榨,這個地方就復雜了舰罚,也不是核心點。
又是一條分割線薛耻。
到這里之后营罢,Advisor的篩選過程我們算是講完了。
經(jīng)過排序之后饼齿,我們算是拿到了這個目標類使用的 Advisors 鏈饲漾。
小結
到這里瘟滨,大家可以回顧一下,我們總算是把TODO-1
【Spring AOP 如何 獲取對應 Bean 適配的Advisors 鏈】介紹完畢了能颁,總結一下核心邏輯就是:
- 獲取當前 IoC 容器中所有的 Aspect 類
- 給 每個Aspect 類的advice 方法創(chuàng)建一個 Spring Advisor杂瘸,這一步又能細分為
- 遍歷所有advice 方法
- 解析方法的注解和pointcut
- 實例化 Advisor 對象
- 獲取到 候選的 Advisors,并且緩存起來伙菊,方便下一次直接獲取
- 從候選的 Advisors 中篩選出與目標類 適配的Advisor
- 獲取到 Advisor 的 切入點 pointcut
- 獲取到 當前 target 類 所有的 public 方法
- 遍歷方法败玉,通過 切入點 的 methodMatcher 匹配當前方法,只有有一個匹配成功就相當于當前的Advisor 適配
- 對篩選之后的 Advisor 鏈進行排序
- 結束
下一節(jié)中镜硕,我們會介紹 【代理類的創(chuàng)建過程】运翼,我們下次再會。