該系列文章是本人在學習 Spring 的過程中總結下來的,裡面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼註釋 Spring 原始碼分析 GitHub 地址 進行閱讀。
Spring 版本:5.1.14.RELEASE
在開始閱讀 Spring AOP 原始碼之前,需要對 Spring IoC 有一定的瞭解,可檢視我的 《死磕Spring之IoC篇 - 文章導讀》 這一系列文章
瞭解 AOP 相關術語,可先檢視 《Spring AOP 常見面試題) 》 這篇文章
該系列其他文章請檢視:《死磕 Spring 之 AOP 篇 - 文章導讀》
在上一篇《Spring AOP 自動代理(一)入口》文章中,分析了 Spring AOP 自動代理的入口是 AbstractAutoProxyCreator 物件,其中自動代理的過程主要分為下面兩步:
- 篩選出能夠應用於當前 Bean 的 Advisor
- 找到了合適 Advisor 則建立一個代理物件, JDK 動態代理或者 CGLIB 動態代理
本文就接著上篇文章來分析篩選合適的通知器的處理過程,包含 @AspectJ
等 AspectJ
註解的解析過程。這裡的“通知器”指的是 Advisor 物件。
回顧
// AbstractAutoProxyCreator.java
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
/*
* <1> 如果當前 Bean 已經建立過自定義 TargetSource 物件
* 表示在上面的**例項化前置處理**中已經建立代理物件,那麼直接返回這個物件
*/
if (StringUtils.hasLength(beanName)
&& this.targetSourcedBeans.contains(beanName))
{
return bean;
}
// <2> `advisedBeans` 儲存了這個 Bean 沒有必要建立代理物件,則直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
/*
* <3> 不需要建立代理物件,則直接返回當前 Bean
*/
if (isInfrastructureClass(bean.getClass()) // 如果是 Spring 內部的 Bean(Advice、Pointcut、Advisor 或者 AopInfrastructureBean 標記介面)
|| shouldSkip(bean.getClass(), beanName)) // 應該跳過
{
// 將這個 Bean 不需要建立代理物件的結果儲存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// <4> 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// <5> 如果有 Advisor,則進行下面的動態代理建立過程
if (specificInterceptors != DO_NOT_PROXY) {
// <5.1> 將這個 Bean 已建立代理物件的結果儲存至 `advisedBeans`
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// <5.2> 建立代理物件,JDK 動態代理或者 CGLIB 動態代理
// 這裡傳入的是 SingletonTargetSource 物件,可獲取代理物件的目標物件(當前 Bean)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// <5.3> 將代理物件的 Class 物件(目標類的子類)儲存
this.proxyTypes.put(cacheKey, proxy.getClass());
// <5.4> 返回代理物件
return proxy;
}
// <6> 否則,將這個 Bean 不需要建立代理物件的結果儲存起來
this.advisedBeans.put(cacheKey, Boolean.FALSE);
// <7> 返回這個 Bean 物件
return bean;
}
在建立代理物件的過程中,上面方法的第 4
步呼叫 getAdvicesAndAdvisorsForBean(..)
方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
// AbstractAutoProxyCreator.java
protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,
@Nullable TargetSource customTargetSource) throws BeansException;
抽象方法,交由子類實現
篩選出合適的 Advisor 的流程
-
解析出當前 IoC 容器所有 Advisor 物件
-
獲取當前 IoC 容器所有 Advisor 型別的 Bean
-
解析當前 IoC 容器中所有帶有
@AspectJ
註解的 Bean,將內部帶有@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解的方法解析出對應的 PointcutAdvisor 物件,帶有@DeclareParents
註解的欄位解析出 IntroductionAdvisor 物件@Around
-> AspectJAroundAdvice,實現了 MethodInterceptor@Before
-> AspectJMethodBeforeAdvice@After
-> AspectJAfterAdvice,實現了 MethodInterceptor@AfterReturning
-> AspectJAfterAdvice@AfterThrowing
-> AspectJAfterThrowingAdvice,實現了 MethodInterceptor
-
-
篩選出能夠應用於這個 Bean 的 Advisor 們,主要通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行匹配
-
對篩選出來的 Advisor 進行擴充套件,例如子類會往首部新增一個 PointcutAdvisor 物件
-
對篩選出來的 Advisor 進行排序
-
不同的 AspectJ 根據
@Order
排序 -
同一個 AspectJ 中不同 Advisor 的排序,優先順序:
AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
-
主要涉及到下面幾個類:
- AbstractAdvisorAutoProxyCreator:支援從當前 Spring 上下文獲取所有 Advisor 物件
- AnnotationAwareAspectJAutoProxyCreator:支援從帶有
@AspectJ
註解 Bean 中解析 Advisor 物件 - BeanFactoryAspectJAdvisorsBuilder:Advisor 構建器,用於解析出當前 BeanFactory 中所有帶有
@AspectJ
註解的 Bean 中的 Advisor - ReflectiveAspectJAdvisorFactory:Advisor 工廠,用於解析
@AspectJ
註解的 Bean 中的 Advisor
AnnotationAwareAspectJAutoProxyCreator 繼承 AbstractAdvisorAutoProxyCreator,藉助 BeanFactoryAspectJAdvisorsBuilder 構建器,這個構建器又藉助 ReflectiveAspectJAdvisorFactory 工廠。
AbstractAdvisorAutoProxyCreator
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator
:支援從當前 Spring 上下文獲取所有 Advisor 物件,存在能應用與 Bean 的 Advisor 則建立代理物件
建構函式
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
/** Advisor 檢索工具類 */
@Nullable
private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
// 初始化工作
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 設定 Advisor 檢索工具類為 BeanFactoryAdvisorRetrievalHelperAdapter
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
}
1. getAdvicesAndAdvisorsForBean 方法
getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource)
,篩選某個 Bean 合適的 Advisor,如下:
@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
// 獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
// 轉換成陣列並返回
return advisors.toArray();
}
呼叫 findEligibleAdvisors(Class<?> beanClass, String beanName)
方法,獲取能夠應用到當前 Bean 的所有 Advisor(已根據 @Order 排序)
2. findEligibleAdvisors 方法
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
/*
* <1> 解析出當前 IoC 容器所有的 Advisor 物件
* 1. 本身是 Advisor 型別的 Bean,預設情況下都會
* 2. 從帶有 @AspectJ 註解的 Bean 中解析出來的 Advisor,子類 AnnotationAwareAspectJAutoProxyCreator 會掃描並解析
* PointcutAdvisor:帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解的方法
* 其中 Pointcut 為 AspectJExpressionPointcut,Advice 就是註解標註的方法
* IntroductionAdvisor:帶有 @DeclareParents 註解的欄位
*
* 未排序,獲取到的 Advisor 在同一個 AspectJ 中的順序是根據註解來的,@Around > @Before > @After > @AfterReturning > @AfterThrowing
*/
List<Advisor> candidateAdvisors = findCandidateAdvisors();
/*
* <2> 篩選出能夠應用到 `beanClass` 上面的所有 Advisor 物件並返回
* 也就是通過 ClassFilter 進行匹配,然後再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
* AspectJExpressionPointcut 就實現了 ClassFilter 和 MethodMatcher
*/
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
/*
* <3> 抽象方法,交由子類擴充
* 例如 AspectJAwareAdvisorAutoProxyCreator 的實現
* 如果 `eligibleAdvisors` 中存在和 AspectJ 相關的 Advisor
* 則會在 `eligibleAdvisors` 首部新增一個 DefaultPointcutAdvisor 物件,對應的 Advice 為 ExposeInvocationInterceptor 物件
* 用於暴露 MethodInvocation 物件(Joinpoint 物件),儲存在 ThreadLocal 中,在其他地方則可以使用
*/
extendAdvisors(eligibleAdvisors);
// <4> 對 `eligibleAdvisors` 集合進行排序,根據 @Order 註解進行排序
if (!eligibleAdvisors.isEmpty()) {
// 不同的 AspectJ 根據 @Order 排序
// 同一個 AspectJ 中不同 Advisor 的排序:AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
// <5> 返回排序後的能夠應用到當前 Bean 的所有 Advisor
return eligibleAdvisors;
}
該方法的處理過程如下:
- 呼叫
findCandidateAdvisors()
方法,解析出當前 IoC 容器所有的 Advisor 物件,得到candidateAdvisors
集合,來源:- 本身是 Advisor 型別的 Bean,預設情況下都會
- 從帶有
@AspectJ
註解的 Bean 中解析出來的 Advisor
- 呼叫
findAdvisorsThatCanApply(..)
方法,篩選出能夠應用到beanClass
上面的所有 Advisor 物件並返回,得到eligibleAdvisors
集合- 通過 ClassFilter 進行匹配,然後再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
- 呼叫
extendAdvisors(List<Advisor> candidateAdvisors)
方法,對eligibleAdvisors
進行處理 - 呼叫
sortAdvisors(List<Advisor> advisors)
方法,對eligibleAdvisors
進行排序 - 返回排序後的能夠應用到當前 Bean 的所有 Advisor
接下來依次對上面的方法進行分析
2.1.1 findCandidateAdvisors 方法
findCandidateAdvisors()
,該方法會去找符合條件的 Advisor 們,AbstractAdvisorAutoProxyCreator 的實現則是去找當前 IoC 容器中所有 Advisor 型別的 Bean,如下:
// AbstractAdvisorAutoProxyCreator.java
protected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
// 藉助 BeanFactoryAdvisorRetrievalHelperAdapter 從 IoC 容器中查詢所有的 Advisor 物件
return this.advisorRetrievalHelper.findAdvisorBeans();
}
可以看到是藉助於 BeanFactoryAdvisorRetrievalHelperAdapter 去找 Advisor 型別的 Bean,如下:
// BeanFactoryAdvisorRetrievalHelperAdapter.java
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
// <1> 先從快取中獲取所有 Advisor
String[] advisorNames = this.cachedAdvisorBeanNames;
// <2> 沒有快取
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// <2.1> 從當前 BeanFactory 容器中找到所有 Advisor 型別的 bean 的名稱
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
// <2.2> 放入快取中
this.cachedAdvisorBeanNames = advisorNames;
}
// <3> 如果沒有 Advisor,則返回一個空集合
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
/*
* <4> 遍歷所有的 Advisor 型別的 Bean 的名稱,獲取對應的 Bean
*/
for (String name : advisorNames) {
// <4.1> 判斷這個 Bean 是否有資格,預設為 true
if (isEligibleBean(name)) {
// <4.2> 正在初始化,則先跳過
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
// <4.3> 否則,獲取對應的 Bean
else {
try {
// 依賴查詢到這個 Advisor 物件
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
// ...
throw ex;
}
}
}
}
// <5> 返回 IoC 容器中所有的 Advisor
return advisors;
}
該方法的處理過程如下:
-
先從快取中獲取所有 Advisor
-
沒有快取
- 從當前 BeanFactory 容器中找到所有 Advisor 型別的 Bean 的名稱
- 放入快取中
-
如果沒有 Advisor,則返回一個空集合
-
遍歷所有的 Advisor 型別的 Bean 的名稱,獲取對應的 Bean
- 判斷這個 Bean 是否有資格,預設為
true
- 正在初始化,則先跳過
- 否則,獲取對應的 Bean,依賴查詢到這個 Advisor 物件
- 判斷這個 Bean 是否有資格,預設為
-
返回 IoC 容器中所有的 Advisor
總結下來,就是從當前 Spring IoC 容器中找到所有 Advisor 型別的 Bean
2.2 findAdvisorsThatCanApply 方法
findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName)
方法,從 candidateAdvisors
中找到能夠應用於 beanClass
的 Advisor,如下:
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
/*
* 篩選出能夠應用到 `beanClass` 上面的所有 Advisor 物件並返回
* 也就是通過 ClassFilter 進行匹配,然後再通過 MethodMatcher 對所有方法進行匹配(有一個即可)
* AspectJExpressionPointcut 就實現了 ClassFilter 和 MethodMatcher
*/
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
可以看到是藉助於 AopUtils 工具類從 candidateAdvisors
中找到能夠應用於 beanClass
的 Advisor,如下:
// AopUtils.java
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new ArrayList<>();
/*
* <1> 遍歷所有的 Advisor 物件
* 找到能夠應用當前 Bean 的 IntroductionAdvisor 物件,放入 `eligibleAdvisors` 集合中
*/
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor // 如果是 IntroductionAdvisor 型別
&& canApply(candidate, clazz)) // 且能夠應用到當前 Bean 中,通過其 ClassFilter 進行過濾
{
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
/*
* <2> 遍歷所有的 Advisor 物件
* 如果是 IntroductionAdvisor 型別,則會跳過,因為上面已經判斷過
* 找到能夠應用當前 Bean 的 Advisor 物件,放入 `eligibleAdvisors` 集合中
*/
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 判斷是否能夠應用到這個 Bean 上面
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
// <3> 返回能夠應用到當前 Bean 的所有 Advisor 物件
return eligibleAdvisors;
}
該方法的處理過程如下:
-
遍歷所有的 Advisor 物件,找到能夠應用當前 Bean 的
IntroductionAdvisor
物件,放入eligibleAdvisors
集合中,需要滿足下面兩個條件- 是
IntroductionAdvisor
型別 - 能夠應用到當前 Bean 中,通過其 ClassFilter 進行過濾
- 是
-
遍歷所有的 Advisor 物件,找到能夠應用當前 Bean 的 Advisor 物件,放入
eligibleAdvisors
集合中;如果是IntroductionAdvisor
型別,則會跳過,因為上面已經判斷過 -
返回能夠應用到當前 Bean 的所有 Advisor 物件
AopUtils#canApply 方法
如何判斷這個 Advisor 能夠應用於某個 Bean 都是呼叫 canApply(..)
方法如下:
// AopUtils.java
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
/*
* 從 IntroductionAdvisor 中獲取 ClassFilter 類過濾器,判斷這個目標類是否符合條件
*/
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
/*
* 根據 Pointcut 中的 ClassFilter 和 MethodFilter 進行過濾
* 例如 Aspect 的實現類 AspectJExpressionPointcut
*/
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
// 否則,沒有 Pointcut,也就是沒有篩選條件,則都符合條件
return true;
}
}
如果 IntroductionAdvisor
型別的 Advisor 則通過 ClassFilter 類過濾器進行判斷即可;如果是 PointcutAdvisor
型別的 Advisor 則需要呼叫 canApply(..)
的過載方法進行判斷;否則,沒有 Pointcut,也就是沒有篩選條件,則都符合條件
AopUtils#canApply 過載方法
如何判斷 PointcutAdvisor
型別的 Advisor 能夠應用於某個 Bean 的過程如下:
// AopUtils.java
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
// <1> 使用 ClassFilter 匹配 `targetClass`
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// <2> 獲取 MethodMatcher 方法匹配器
MethodMatcher methodMatcher = pc.getMethodMatcher();
// <3> 如果方法匹配器為 TrueMethodMatcher,則預設都通過
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
// <4> 如果方法匹配器為 IntroductionAwareMethodMatcher,則進行轉換
// AspectJExpressionPointcut 就是 IntroductionAwareMethodMatcher 的實現類
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
/*
* <5> 獲取目標類、以及實現的所有介面,並新增至 `classes` 集合中
*/
Set<Class<?>> classes = new LinkedHashSet<>();
// <5.1> 如果不是 java.lang.reflect.Proxy 的子類
if (!Proxy.isProxyClass(targetClass)) {
// 獲取目標類的 Class 物件(如果目標類是 CGLIB 代理物件,則獲取其父類的 Class 物件,也就得到了目標類)
classes.add(ClassUtils.getUserClass(targetClass));
}
// <5.2> 獲取目標類實現的所有介面,如果目標類本身是一個介面,那麼就取這個目標類
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
/*
* <6> 遍歷上面的 `classes` 集合
*/
for (Class<?> clazz : classes) {
// <6.1> 獲取這個 Class 物件的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// <6.2> 遍歷上一步獲取到的所有方法
for (Method method : methods) {
// <6.3> 使用方法匹配器對該方法進行匹配,如果匹配成功則直接返回 `true`
// AspectJExpressionPointcut 底層就是通過 AspectJ 進行處理的
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
// <7> 一個方法都沒匹配則返回 `false`,表示這個 Advisor 不能應用到這個 Bean 上面
return false;
}
該方法的處理過程如下:
- 使用 Pointcut 的 ClassFilter 匹配
targetClass
,不通過則直接返回false
- 獲取 Pointcut 的 MethodMatcher 方法匹配器,儲存至
methodMatcher
- 如果
methodMatcher
為 TrueMethodMatcher,則預設都通過,返回true
- 如果
methodMatcher
為 IntroductionAwareMethodMatcher,則進行轉換,儲存至introductionAwareMethodMatcher
- AspectJExpressionPointcut 就是 IntroductionAwareMethodMatcher 的實現類
- 獲取目標類、以及實現的所有介面,並新增至
classes
集合中- 如果不是 java.lang.reflect.Proxy 的子類,則獲取
targetClass
目標類的 Class 物件(如果目標類是 CGLIB 代理物件,則獲取其父類的 Class 物件,也就得到了目標類) - 獲取
targetClass
目標類實現的所有介面,如果目標類本身是一個介面,那麼就取這個目標類
- 如果不是 java.lang.reflect.Proxy 的子類,則獲取
- 遍歷上面的
classes
集合- 獲取這個 Class 物件的所有方法
- 遍歷上一步獲取到的所有方法
- 使用
methodMatcher
方法匹配器對該方法進行匹配,優先使用introductionAwareMethodMatcher
方法匹配器,匹配成功則直接返回true
,說明有一個方法滿足條件即可- AspectJExpressionPointcut 底層就是通過 AspectJ 的表示式處理進行處理的
- 一個方法都沒匹配成功則返回
false
,表示這個 Advisor 不能應用到這個 Bean 上面
總結下來,PointcutAdvisor 是根據 Pointcut 的 ClassFilter 對目標類進行過濾,如果通過的話,則通過 MethodMatcher 方法匹配器對目標類的方法進行匹配,有一個方法滿足條件就表示這個 PointcutAdvisor 可以應用於目標類
2.3 extendAdvisors 方法
extendAdvisors(List<Advisor> candidateAdvisors)
放,對篩選出來的 Advisor 進行擴充套件,抽象方法,我們來看到子類的實現:
// AspectJAwareAdvisorAutoProxyCreator.java
@Override
protected void extendAdvisors(List<Advisor> candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
可以看到是藉助於 AspectJProxyUtils 工具類進行擴充套件,如下:
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
// Don't add advisors to an empty list; may indicate that proxying is just not required
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
// 遍歷所有 Advisor
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as this might eagerly
// instantiate a non-singleton AspectJ aspect...
// 判斷這個 Advisor 是否和 AspectJ 相關
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
break;
}
}
// 如果 `advisors` 涉及到和 AspectJ 相關的 Advisor
// 則向其首部新增一個 DefaultPointcutAdvisor 物件,對應的 Advice 為 ExposeInvocationInterceptor 物件
// 用於暴露 MethodInvocation 物件(Joinpoint 物件),儲存在 ThreadLocal 中,在其他地方則可以使用
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
private static boolean isAspectJAdvice(Advisor advisor) {
return ( advisor instanceof InstantiationModelAwarePointcutAdvisor
|| advisor.getAdvice() instanceof AbstractAspectJAdvice
|| ( advisor instanceof PointcutAdvisor && ((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut) );
}
處理過程很簡單,當存在和 AspectJ 相關的 Advisor(使用了 AspectJ 的註解這裡都是 true
),則在首部新增一個 DefaultPointcutAdvisor 物件
新增的這個 Advisor 對應的 Advice 為 ExposeInvocationInterceptor 方法攔截器,用於暴露 MethodInvocation 物件(Joinpoint 物件),儲存在 ThreadLocal 中,在其他地方則可以使用
2.4 sortAdvisors 方法
sortAdvisors(List<Advisor> advisors)
方法,對篩選出來的 Advisor 進行排序,如下:
// AspectJAwareAdvisorAutoProxyCreator.java
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
for (Advisor element : advisors) {
// 使用 AspectJPrecedenceComparator 比較器
partiallyComparableAdvisors.add(
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
}
List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
if (sorted != null) {
List<Advisor> result = new ArrayList<>(advisors.size());
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
result.add(pcAdvisor.getAdvisor());
}
return result;
}
else {
// AbstractAdvisorAutoProxyCreator
// 使用 AnnotationAwareOrderComparator 比較器,通過 @Order 註解
return super.sortAdvisors(advisors);
}
}
AspectJPrecedenceComparator 是對 AnnotationAwareOrderComparator 的包裝,進行了擴充套件,排序不同型別的 Advice,詳細的過程這裡不展述了
我通過 Debug 打斷點得到的結論:
-
不同的 AspectJ 根據
@Order
排序 -
同一個 AspectJ 中不同 Advisor 的排序,優先順序如下:
AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
小結
到這裡我們可以一個結論,篩選合適的通知器的總的過程在 AbstractAdvisorAutoProxyCreator#findEligibleAdvisors(..) 方法中進行,分為下面幾步:
- 找符合條件的 Advisor 們,在 AbstractAdvisorAutoProxyCreator 則是去找當前 IoC 容器中所有 Advisor 型別的 Bean
- 從上一步找到的 Advisor 篩選出能夠應用於當前 Bean 的 Advisor 們,主要是通過 Pointcut 的 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行判斷,有一個方法匹配這個 Advisor 即滿足條件
- 支援對找到的 Advisor 集合進行擴充套件,在子類中會往其首部新增一個方法攔截器為 ExposeInvocationInterceptor 的 PointcutAdvisor
- 對找到的合適的 Advisor 進行排序,排序結果如上所述
上面過程的第 1
步僅找到當前 IoC 容器中所有 Advisor 型別的 Bean,是不是沒有對 AspectJ 相關注解進行解析,這個過程在子類中實現,也就是接下來要講的內容
AnnotationAwareAspectJAutoProxyCreator
org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
:支援從帶有 @AspectJ
註解 Bean 中解析 Advisor 物件
建構函式
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
/**
* 用於指定哪些 Bean 能夠作為 Advisor
*/
@Nullable
private List<Pattern> includePatterns;
/**
* 解析 AspectJ 註解的 Advisor 工廠
*/
@Nullable
private AspectJAdvisorFactory aspectJAdvisorFactory;
/**
* 構建器模式,用於構建 AspectJ 註解的 Advisor
*/
@Nullable
private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 初始化 BeanFactoryAdvisorRetrievalHelperAdapter
super.initBeanFactory(beanFactory);
// 初始化 ReflectiveAspectJAdvisorFactory
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
// 初始化 BeanFactoryAspectJAdvisorsBuilderAdapter
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
}
2.1.2 findCandidateAdvisors 方法
findCandidateAdvisors()
,該方法會去找符合條件的 Advisor 們,通過父類找到當前 IoC 容器中所有 Advisor 型別的 Bean,這裡又會解析出帶有 @AspectJ
註解的 Bean 中的 Advisor 們,如下:
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// <1> 呼叫父類方法,從 IoC 容器中查詢所有的 Advisor 型別的 Bean
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
// <2> 如果 AspectJ 解析器不為空,預設為 BeanFactoryAspectJAdvisorsBuilderAdapter
if (this.aspectJAdvisorsBuilder != null) {
// 解析所有帶有 @AspectJ 註解的 Bean
// 其中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解的方法會被解析成一個 PointcutAdvisor 物件
// 將解析出來的所有 Advisor 新增至 `advisors` 中
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
// <3> 返回 `advisors` 集合(當前 IoC 容器中解析出來的所有的 Advisor 物件)
return advisors;
}
該方法的處理過程如下:
- 呼叫父類方法,從 IoC 容器中查詢所有的 Advisor 型別的 Bean,儲存至
advisors
中,可返回上面的2.1.1 findCandidateAdvisors 方法
小節檢視 - 如果 AspectJ 解析器不為空,預設為 BeanFactoryAspectJAdvisorsBuilderAdapter,則通過它解析出 Advisor 來
- 解析所有帶有
@AspectJ
註解的 Bean - 其中帶有
@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解的方法會被解析成一個 PointcutAdvisor 物件 - 將解析出來的所有 Advisor 新增至
advisors
中
- 解析所有帶有
- 返回
advisors
集合(當前 IoC 容器中解析出來的所有的 Advisor 物件)
BeanFactoryAspectJAdvisorsBuilderAdapter
關於 @AspectJ
註解的解析由 BeanFactoryAspectJAdvisorsBuilderAdapter 完成,如下:
// AnnotationAwareAspectJAutoProxyCreator.java
private class BeanFactoryAspectJAdvisorsBuilderAdapter extends BeanFactoryAspectJAdvisorsBuilder {
public BeanFactoryAspectJAdvisorsBuilderAdapter(
ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
super(beanFactory, advisorFactory);
}
@Override
protected boolean isEligibleBean(String beanName) {
return AnnotationAwareAspectJAutoProxyCreator.this.isEligibleAspectBean(beanName);
}
}
protected boolean isEligibleAspectBean(String beanName) {
if (this.includePatterns == null) {
return true;
} else {
for (Pattern pattern : this.includePatterns) {
if (pattern.matcher(beanName).matches()) {
return true;
}
}
return false;
}
}
這裡只重寫了 isEligibleBean(String)
方法,用於判斷這個 Bean 是否有資格作為一個 Advisor。可以看到是通過 includePatterns
對 beanName
進行判斷,匹配通過才有資格。當然,includePatterns
一般為空,都有資格。
這個類繼承了 BeanFactoryAspectJAdvisorsBuilder 構建器,我們來看到這個構建器是如何解析的。
BeanFactoryAspectJAdvisorsBuilder
org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder
,Advisor 構建器,用於解析出當前 BeanFactory 中所有帶有 @AspectJ
註解的 Bean 中的 Advisor
建構函式
public class BeanFactoryAspectJAdvisorsBuilder {
/**
* 當前 IoC 容器,DefaultListableBeanFactory
*/
private final ListableBeanFactory beanFactory;
/**
* Advisor 工廠,用於解析 @AspectJ 註解的 Bean 中的 Advisor
*/
private final AspectJAdvisorFactory advisorFactory;
/**
* 用於快取帶有 @AspectJ 註解的 Bean 的名稱
*/
@Nullable
private volatile List<String> aspectBeanNames;
/**
* 快取 @AspectJ 註解的單例 Bean 中解析出來的 Advisor
* key:帶有 @AspectJ 註解的 beanName
* value:其內部解析出來的 Advisor 集合
*/
private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();
/**
* 快取 @AspectJ 註解的非單例 Bean 的後設資料例項構建工廠
* key:帶有 @AspectJ 註解的 beanName(非單例)
* value:對應的後設資料工廠物件
*/
private final Map<String, MetadataAwareAspectInstanceFactory> aspectFactoryCache = new ConcurrentHashMap<>();
public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
this.beanFactory = beanFactory;
this.advisorFactory = advisorFactory;
}
}
2.1.3 buildAspectJAdvisors 方法
buildAspectJAdvisors()
方法,解析出當前 BeanFactory 中所有帶有 @AspectJ
註解的 Bean 中的 Advisor,如下:
public List<Advisor> buildAspectJAdvisors() {
// <1> 從快取中獲取所有帶有 @AspectJ 註解的 Bean,儲存至 `aspectNames` 集合中
List<String> aspectNames = this.aspectBeanNames;
// <2> 快取中沒有,則對當前物件加鎖再判斷快取中是否有資料
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
// <3> 還是沒有快取,則進行接下來的處理
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
// <3.1> 獲取當前 IoC 容器中所有的 Bean 的名稱集合
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// <3.2> 遍歷所有的 Bean 的名稱,進行處理
for (String beanName : beanNames) {
// <3.3> 判斷這個 Bean 是否有資格,預設都為 true
if (!isEligibleBean(beanName)) {
// 如果沒有資格則跳過
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// <3.4> 獲取這個 Bean 的 Class 物件,如果為空則跳過
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// <3.5> 如果這個 Bean 帶有 @Aspect 註解,且沒有以 `ajc$` 開頭的欄位,那麼進行接下來的解析過程
if (this.advisorFactory.isAspect(beanType)) {
// <3.5.1> 將這個 Bean 的名稱儲存至 `aspectNames` 集合中
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// <3.5.2> 判斷 @AspectJ 註解的類別是否為 `singleton`,預設空的情況就是這個
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// <3.5.2.1> 解析這個 Bean 中帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解的方法
// 會解析成對應的 InstantiationModelAwarePointcutAdvisorImpl 物件(PointcutAdvisor)
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// <3.5.2.2> 如果這個 Bean 是單例模式,則將解析出來的 Advisor 全部快取至 `advisorsCache` 中
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
// <3.5.2.3> 否則,將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 後設資料例項構建工廠)快取至 `aspectFactoryCache` 中
else {
this.aspectFactoryCache.put(beanName, factory);
}
// <3.5.2.4> 將解析出來的 Advisor 新增至 `advisors` 中
advisors.addAll(classAdvisors);
}
// <3.5.3> 否則,這個 AspectJ 不是單例模式,不能將解析出來的 Advisor 快取,其他的處理過程都和上面一樣
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 後設資料例項構建工廠)快取至 `aspectFactoryCache` 中
this.aspectFactoryCache.put(beanName, factory);
// 解析出這個 Bean 中所有的 Advisor,並新增至 `advisors` 中
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
// <3.6> 對 `aspectNames` 進行快取
this.aspectBeanNames = aspectNames;
// <3.7> 返回所有 AspectJ 的所有的 Advisor 物件們
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
/*
* <4> 否則,遍歷快取中的 AspectJ 的 beanName
*/
for (String aspectName : aspectNames) {
// <4.1> 嘗試從 `advisorsCache` 快取中獲取這個 beanName 對應的所有 Advisor 們,並新增至 `advisors` 中
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
// <4.2> `advisorsCache` 快取中沒有,
// 則根據 `aspectFactoryCache` 快取中對應的 MetadataAwareAspectInstanceFactory(AspectJ 後設資料例項構建工廠)解析出所有的 Advisor 們,並新增至 `advisors` 中
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
// <5> 返回所有 AspectJ 的所有的 Advisor 物件們
return advisors;
}
該方法的處理過程稍微有點複雜,如下:
- 從快取中獲取所有帶有
@AspectJ
註解的 Bean,儲存至aspectNames
集合中 - 快取中沒有,則對當前物件加鎖再判斷快取中是否有資料
- 還是沒有快取,則進行接下來的處理
- 獲取當前 IoC 容器中所有的 Bean 的名稱集合
- 遍歷所有的 Bean 的名稱,進行處理
- 判斷這個 Bean 是否有資格,預設都為
true
- 獲取這個 Bean 的 Class 物件,如果為空則跳過
- 如果這個 Bean 帶有
@Aspect
註解,且沒有以ajc$
開頭的欄位,那麼進行接下來的解析過程- 將這個 Bean 的名稱儲存至
aspectNames
集合中 - 判斷
@AspectJ
註解的類別是否為singleton
,預設空的情況就是這個- 通過
AspectJAdvisorFactory#getAdvisors(..)
方法解析出這個 Bean 中帶有@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解的方法,例如會解析成 InstantiationModelAwarePointcutAdvisorImpl 物件(PointcutAdvisor) - 如果這個 Bean 是單例模式,則將解析出來的 Advisor 全部快取至
advisorsCache
中 - 否則,將這個 Bean 對應的 MetadataAwareAspectInstanceFactory(AspectJ 後設資料例項構建工廠)快取至
aspectFactoryCache
中 - 將解析出來的 Advisor 新增至
advisors
中
- 通過
- 否則,這個 AspectJ 不是單例模式,不能將解析出來的 Advisor 快取,其他的處理過程都和上面一樣
- 將這個 Bean 的名稱儲存至
- 對
aspectNames
進行快取 - 返回所有 AspectJ 的所有的 Advisor 物件們
- 否則,遍歷快取中的 AspectJ 的
beanName
,進行處理- 嘗試從
advisorsCache
快取中獲取這個beanName
對應的所有 Advisor 們,並新增至advisors
中 advisorsCache
快取中沒有,則根據aspectFactoryCache
快取中對應的 MetadataAwareAspectInstanceFactory(AspectJ 後設資料例項構建工廠)解析出所有的 Advisor 們,並新增至advisors
中
- 嘗試從
- 返回所有 AspectJ 的所有的 Advisor 物件們
做個小結,整個過程稍微複雜一點,會嘗試從快取中獲取 Advisor,快取中沒有資料則先獲取到所有帶有 @AspectJ
註解的 Bean,通過 ReflectiveAspectJAdvisorFactory 對這些 Bean 中帶有 AspectJ 相關注解的方法進行處理,生成對應的 PointcutAdvisor 物件。
接下來,我們來看看 ReflectiveAspectJAdvisorFactory 解析 @AspectJ
註解的 Bean 的過程
ReflectiveAspectJAdvisorFactory
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
,Advisor 工廠,用於解析 @AspectJ
註解的 Bean 中的 Advisor
建構函式
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
/**
* 方法比較器
*/
private static final Comparator<Method> METHOD_COMPARATOR;
static {
Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
new InstanceComparator<>( Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
(Converter<Method, Annotation>) method -> {
AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (annotation != null ? annotation.getAnnotation() : null);
});
Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
}
}
可以看到有一個 Comparator 方法比較器,順序是 @Around > @Before > @After > @AfterReturning > @AfterThrowing
,注意獲取到應用於某個 Bean 的 Advisor 的順序不是這樣子,可以回到前面的 2.4 sortAdvisors 方法
小節看看
2.1.3.1 getAdvisors 方法
getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory)
方法,解析出這個 Bean(帶有 @AspectJ
註解)中所有的 Advisor,方法入參是 Bean 的後設資料例項構建工廠,方法如下:
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// <1> 獲取這個 Bean 的 Class 物件和 beanName
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
/*
* <2> 遍歷沒有標註 @Pointcut 註解的方法(順序:@Around > @Before > @After > @AfterReturning > @AfterThrowing)
*/
for (Method method : getAdvisorMethods(aspectClass)) {
/*
* <2.1> 如果這個方法帶有 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解
* 則根據註解資訊建立一個 InstantiationModelAwarePointcutAdvisorImpl 物件
* 這個物件就是 PointcutAdvisor 型別,包含了 Pointcut 和 Advice
*/
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
// <2.2> 生成了 PointcutAdvisor 則新增至 `advisor` 集合中
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
// <3> 如果這個 Aspect 需要延遲初始化,則往首部新增一個 PointcutAdvisor
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// <4> 根據帶有 @DeclareParents 註解的欄位生成 IntroductionAdvisor 物件,並新增至 `advisor` 集合中
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
// <5> 返回這個 Aspect 中所有的 Advisor 物件
return advisors;
}
該方法的處理過程如下:
-
獲取這個 Bean 的 Class 物件和
beanName
-
遍歷沒有標註
@Pointcut
註解的方法(順序:@Around > @Before > @After > @AfterReturning > @AfterThrowing
)private List<Method> getAdvisorMethods(Class<?> aspectClass) { final List<Method> methods = new ArrayList<>(); ReflectionUtils.doWithMethods(aspectClass, method -> { // Exclude pointcuts // 排除 @Pointcut 註解標註的方法 if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) { methods.add(method); } }); // 進行排序 methods.sort(METHOD_COMPARATOR); return methods; }
- 呼叫
getAdvisor(..)
方法,將這個方法解析成 InstantiationModelAwarePointcutAdvisorImpl 物件(PointcutAdvisor),這個方法必須帶有@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解 - 如果上一步解析出了 Advisor 物件,則新增至
advisor
集合中
- 呼叫
-
如果這個 Aspect 需要延遲初始化,則往首部新增一個 SyntheticInstantiationAdvisor(PointcutAdvisor),暫時忽略
-
呼叫
getDeclareParentsAdvisor(..)
方法,根據帶有@DeclareParents
註解的欄位生成 IntroductionAdvisor 物件,並新增至advisor
集合中private Advisor getDeclareParentsAdvisor(Field introductionField) { DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class); if (declareParents == null) { return null; } if (DeclareParents.class == declareParents.defaultImpl()) { throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents"); } return new DeclareParentsAdvisor( introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }
-
返回這個 Aspect 中所有的 Advisor 物件,也就是返回
advisor
集合
可以看到 @AspectJ
註解的 Bean 中的 @Before|@After|@Around|@AfterReturning|@AfterThrowing
註解方法在 getAdvisor(..)
方法中進行
2.1.3.2 getAdvisor 方法
getAdvisor(..)
方法,解析 @Before|@After|@Around|@AfterReturning|@AfterThrowing
註解方法,生成 PointcutAdvisor 物件,如下:
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
/*
* <1> 嘗試根據該方法生成一個 AspectJExpressionPointcut 物件
* 根據 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解資訊進行建立,沒有的話則返回 null
*/
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
/*
* <2> 如果存在上面其中一個註解,則將建立的 AspectJExpressionPointcut 封裝成 InstantiationModelAwarePointcutAdvisorImpl 物件
* 也就是封裝成了 PointcutAdvisor 物件,會初始化一個 Advice,也就是註解標註的方法
* 那麼這個物件中就包含了 Pointcut 和 Advice,就可以判斷某個方法是否被攔截,攔截後應該如何處理
*/
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
該方法的處理過程如下:
- 呼叫
getPointcut(..)
方法,嘗試根據該方法生成一個 AspectJExpressionPointcut 物件,根據@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解資訊進行建立,沒有的話則返回null
- 如果存在上面其中一個註解,則將建立的 AspectJExpressionPointcut 封裝成 InstantiationModelAwarePointcutAdvisorImpl 物件,也就是封裝成了 PointcutAdvisor 物件,會初始化一個 Advice,也就是註解標註的方法。那麼這個物件中就包含了 Pointcut 和 Advice,就可以判斷某個方法是否被攔截,攔截後應該如何處理
getPointcut 方法
getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass)
方法,嘗試將方法解析成 AspectJExpressionPointcut 物件,如下:
private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
// <1> 找到這個方法的 @Before|@After|@Around|@AfterReturning|@AfterThrowing 註解資訊
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// <2> 如果帶有上面其中一個註解,則建立一個 AspectJExpressionPointcut 物件
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
// <3> 設定 Pointcut 的表示式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}
// <4> 返回 AspectJExpressionPointcut 物件
return ajexp;
}
該方法的處理過程如下:
- 找到這個方法的
@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解資訊 - 如果帶有上面其中一個註解,則建立一個 AspectJExpressionPointcut 物件
- 設定 Pointcut 的表示式
- 返回 AspectJExpressionPointcut 物件
getAdvice 方法
getAdvice(..)
方法,主要根據 AspectJExpressionPointcut 初始化一個 Advice 物件,如下:
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 獲取 @Pointcut、@Around、@Before、@After、@AfterReturning、@AfterThrowing 註解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround: // @Around -> AspectJAroundAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore: // @Before -> AspectJMethodBeforeAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: // @After -> AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning: // @AfterReturning -> AspectJAfterAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing: // @AfterThrowing -> AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
/*
* 獲取方法的引數名列表
*/
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 設定引數名
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
根據註解的型別建立對應的 Advice 型別,如下:
@Around
:AspectJAroundAdvice,實現了 MethodInterceptor@Before
:AspectJMethodBeforeAdvice@After
:AspectJAfterAdvice,實現了 MethodInterceptor@AfterReturning
: AspectJAfterAdvice@AfterThrowing
:AspectJAfterThrowingAdvice,實現了 MethodInterceptor
InstantiationModelAwarePointcutAdvisorImpl
org.springframework.aop.aspectj.annotation.InstantiationModelAwarePointcutAdvisorImpl
,AspectJ 註解方法解析後的物件,實現了 PointcutAdvisor,包含 Pointcut 和 Advice
final class InstantiationModelAwarePointcutAdvisorImpl
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
private static final Advice EMPTY_ADVICE = new Advice() {};
private final AspectJExpressionPointcut declaredPointcut;
private final Class<?> declaringClass;
private final String methodName;
private final Class<?>[] parameterTypes;
private transient Method aspectJAdviceMethod;
private final AspectJAdvisorFactory aspectJAdvisorFactory;
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
private final int declarationOrder;
private final String aspectName;
private final Pointcut pointcut;
private final boolean lazy;
@Nullable
private Advice instantiatedAdvice;
@Nullable
private Boolean isBeforeAdvice;
@Nullable
private Boolean isAfterAdvice;
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// AspectJExpressionPointcut 物件
this.declaredPointcut = declaredPointcut;
// Advice 所在的 Class 物件
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
// Advice 對應的方法名稱
this.methodName = aspectJAdviceMethod.getName();
// Advice 對應的方法引數型別
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
// Advice 對應的方法物件
this.aspectJAdviceMethod = aspectJAdviceMethod;
// Advisor 工廠,用於解析 @AspectJ 註解的 Bean 中的 Advisor
this.aspectJAdvisorFactory = aspectJAdvisorFactory;
// 後設資料例項構建工廠
this.aspectInstanceFactory = aspectInstanceFactory;
// 定義的順序
this.declarationOrder = declarationOrder;
// Advice 所在 Bean 的名稱
this.aspectName = aspectName;
// 如果需要延遲初始化,則不立即初始化 Advice 物件
if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// Static part of the pointcut is a lazy type.
Pointcut preInstantiationPointcut = Pointcuts.union(
aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
// Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
// If it's not a dynamic pointcut, it may be optimized out
// by the Spring AOP infrastructure after the first evaluation.
this.pointcut = new PerTargetInstantiationModelPointcut(
this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
this.lazy = true;
}
// 否則,初始化 Advice 物件
else {
// A singleton aspect.
// AspectJExpressionPointcut 物件
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 根據 AspectJExpressionPointcut 初始化一個 Advice 物件
// `@Around`:AspectJAroundAdvice,實現了 MethodInterceptor
// `@Before`:AspectJMethodBeforeAdvice
// `@After`:AspectJAfterAdvice,實現了 MethodInterceptor
// `@AfterReturning`: AspectJAfterAdvice
// `@AfterThrowing`:AspectJAfterThrowingAdvice,實現了 MethodInterceptor
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}
}
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
}
總結
在上一篇《Spring AOP 自動代理(一)入口》文章講述了 Spring AOP 自動代理的入口,主要對 AbstractAutoProxyCreator 這個類進行了分析。本文接著上一篇文章分析了在 Spring AOP 自動代理的的過程中,如何從 Spring 上下文篩選出能夠應用於某個 Bean 的 Advisor 們,大致的流程如下:
-
解析出當前 IoC 容器所有 Advisor 物件
- 獲取當前 IoC 容器所有 Advisor 型別的 Bean
- 解析當前 IoC 容器中所有帶有
@AspectJ
註解的 Bean,將內部帶有@Before|@After|@Around|@AfterReturning|@AfterThrowing
註解的方法解析出對應的 PointcutAdvisor 物件,帶有@DeclareParents
註解的欄位解析出 IntroductionAdvisor 物件
-
篩選出能夠應用於這個 Bean 的 Advisor 們,主要通過 ClassFilter 類過濾器和 MethodMatcher 方法匹配器進行匹配
-
對篩選出來的 Advisor 進行擴充套件,例如子類會往首部新增一個 PointcutAdvisor 物件
-
對篩選出來的 Advisor 進行排序
-
不同的 AspectJ 根據
@Order
排序 -
同一個 AspectJ 中不同 Advisor 的排序,優先順序:
AspectJAfterThrowingAdvice > AspectJAfterReturningAdvice > AspectJAfterAdvice > AspectJAroundAdvice > AspectJMethodBeforeAdvice
-
AspectJ 中的註解對應的 Advice 型別如下:
@Around
-> AspectJAroundAdvice,實現了 MethodInterceptor@Before
-> AspectJMethodBeforeAdvice@After
-> AspectJAfterAdvice,實現了 MethodInterceptor@AfterReturning
-> AspectJAfterAdvice@AfterThrowing
-> AspectJAfterThrowingAdvice,實現了 MethodInterceptor
好了,本篇文章就到這裡了,如果獲取到能夠應用於某個 Bean 的 Advisor,那麼接下來要做的就是為這個 Bean 建立一個代理物件,通過 JDK 動態代理或者 CGLIB 動態代理,將在下篇文章進行分析。