概述
spring-aop
模塊是 Spring 框架中最重要的組件之一,它爲我們提供了強大的 AOP 功能,併爲其他擴展功能(如聲明式事務、聲明式異步處理等)提供了支持。在本文中,我們將深入探討 SpringAOP 的源碼,從代理對象的創建開始,揭示 SpringAOP 的運行機制。
首先,在閱讀這篇文章前,請先確保對 Spring 中 Bean 創建流程有基本的瞭解,因爲實際上這個流程也是 SpringAOP 生效的關鍵。在這個基礎上,我們將聚焦於 SpringAOP 中的後處理器,以及與 AOP 功能密切相關的通知器、通知和切點等組件或概念,通過對這些組件的代碼結構深入認知,我們將更好地理解 SpringAOP 的內部工作原理。
當我們描述 AOP 的時候,它通常包含下述概念/組件:
- 通知
Advice
:是切面邏輯的具體實現,它決定了在切點處執行什麼操作; - 切點
Pointcut
:程序執行過程中的一個特定點,例如方法的調用或異常的拋出,它是通知的觸發點; - 通知器
Advisor
:它代表了要對哪些對象、在哪裏、應用哪些通知,它通常是且不限於是通知和切點的組合體; - 連接點
Joinpoint
:它代表了程序中的某一處位置,通常包含切點切入位置的一些信息,比如MethodInvocation
或ConstructorInvocation
; - 切面
Aspect
:它是AspectJ
的概念,在 Spring 中可以認爲是一個同時包含多種Advisor
的聚合體,實際使用時,我們通過@Aspect
註解聲明的切面中的方法會被轉爲多個Advisor
;
接下來,我們將圍繞着上述內容,展開研究。
本專題共三篇文章,這是第一篇:
- 深入理解 SpringAOP(一):AOP 組件概述;
- 深入理解 SpringAOP(二):AOP的執行流程;
- 深入理解 SpringAOP(三):AspectJ支持;
一、通知器
因此,某種程度上來說,Advisor
就是某個具體切入規則的最小單位。
1、實現體系
通知器 Advisor
本身的方法異常簡單,它只規定“要在哪裏應用哪些通知”,而“對哪些類使用”則交由子類來實現:
public interface Advisor {
// 獲取通知操作,即具體的操作邏輯
Advice getAdvice();
// 每個切入目標是否都需要一個新的通知器
boolean isPerInstance();
}
因此一般 Advisor
不會直接使用,而是轉爲具體的 PointcutAdvisor
和 IntroductionAdvisor
使用。
2、切點通知器
PointcutAdvisor
,直譯即切點通知器,允許通知器提供一個切點類 Pointcut
,用於匹配特定的方法或者類:
public interface PointcutAdvisor extends Advisor {
// 獲取切點,即類或方法匹配器
Pointcut getPointcut();
}
它也是最常見的通知器,Spring 中大部分我們熟知的功能都基於它實現,比如用於處理 @Async
註解的 AsyncAnnotationAdvisor
,與用於處理 @Transcational
註解的 TransactionAttributeSourceAdvisor
(嚴格來說這麼說並不準確,因爲實際上註解是由 TransactionAnnotationParser
處理的,不過這裏我們認爲它們相關)。
3、引介入通知器
IntroductionAdvisor
,直譯即爲引介通知器,比較少用到的通知器,用於實現接口引入——即讓一個 bean 無中生有的獲得特定某些接口的方法,有點類似於 kotlin 的擴展函數:
public interface IntroductionInfo {
// 需要引入的接口,即被切入的類等於變相的實現了這些接口
Class<?>[] getInterfaces();
}
它比較常用的實現應該是 DeclareParentsAdvisor
,用於配合 AspectJ
的 @DeclareParents
做接口引入,不過確實不太常見,因此我們瞭解即可。
二、通知
Advice
即 “通知”,它表示切入對象後,需要“在什麼地方做什麼事”。它的子接口非常多,但是按切入位置可以簡單分爲三類:
- 執行前通知:
BeforeAdvice
; - 環繞通知:
InterceptorAdvice
; - 後置通知:
AfterAdvice
,這裏又分爲返回後通知AfterReturningAdvice
和異常通知ThrowsAdvice
;
比較有趣的是,除了 DynamicIntroductionAdvice
外,Advice
、Interceptor
、BeforeAdvice
和 AfterAdvice
這幾個頂級接口都是沒有抽象方法的標記接口,因此我們可以一般只關注具體的實現接口即可。
方法攔截器與切點
方法攔截器 MethodInterceptor
最常見的 Advice
,我們熟知的絕大部分基於 SpringAOP 提供的功能都依賴它實現——實際上,就算是其他的實現,到最後執行代理方法的時候依然要適配爲 MethodInterceptor
去執行。
public interface MethodInterceptor extends Interceptor {
// 攔截方法調用
@Nullable
Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
}
在這裏,我們就會接觸到 Joinpoint
,也就是切點的概念,MethodInvocation
就是方法切點:
它包含了一次方法調用中的一些已知信息,包括調用的方法、調用的參數等等,最常見的實現是 ReflectiveInvocation
,我們在 AspectJ
中接觸的 JoinPoint
跟它基本一樣。
三、切點
切面 Pointcut
是屬於 PointcutAdvisor
的一個組件,它用於匹配類或者方法:
public interface PointcutAdvisor extends Advisor {
/**
* Get the Pointcut that drives this advisor.
*/
Pointcut getPointcut();
}
切點由類型過濾器 ClassFilter
和方法匹配器 MethodMatcher
兩個組件共同組成:
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
}
當使用時,將僅會攔截 ClassFilter
不過濾的類中與 MethodMatcher
匹配的方法。
比較常用的實現類爲支持對類和方法名進行表達式匹配的 NameMatchMethodPointcut
,與支持 Spring 元註解機制,能夠按照類和方法上註解進行匹配的 AnnotationMatchingPointcut
。
四、後處理器
AOP 發生在 Bean 的創建過程中,它基於特定的後處理器 AbstractAutoProxyCreator
完成,當然,實際上它的背後是一個大家族:
兩個關鍵的抽象類:
AbstractAutoProxyCreator
:AbstractAutoProxyCreator
是一個抽象類,實現了BeanPostProcessor
接口,用於自動創建代理對象。它的作用是在Spring容器中自動檢測符合條件的bean,並對其進行代理。它可以根據一些配置條件(例如bean的名稱、類型、註解等)決定是否對目標bean進行代理,並提供了一些鉤子方法供子類實現自定義的代理邏輯;AbstractAdvisorAutoProxyCreator
:AbstractAdvisorAutoProxyCreator
是AbstractAutoProxyCreator
的子類,它進一步擴展了自動代理的功能。除了AbstractAutoProxyCreator
的功能外,AbstractAdvisorAutoProxyCreator
還能夠通過配置Advisor(通知器)來決定代理的行爲;
兩個關鍵的實現類:
AspectJAwareAdvisorAutoProxyCreator
:AspectJAwareAdvisorAutoProxyCreator
繼承自AbstractAdvisorAutoProxyCreator
,它是Spring AOP的一個關鍵組件之一,用於實現基於AspectJ註解的自動代理。它支持使用AspectJ註解(如@Aspect
、@Pointcut
、@Before
、@After
等)來定義切面,然後根據這些切面的定義,在目標 bean 上應用相應的通知;AnnotationAwareAspectJAutoProxyCreator
:AnnotationAwareAspectJAutoProxyCreator
是AspectJAwareAdvisorAutoProxyCreator
的子類,它進一步擴展了 AspectJ 註解的自動代理功能。與AspectJAwareAdvisorAutoProxyCreator
相比,AnnotationAwareAspectJAutoProxyCreator
提供了更加靈活的註解驅動的 AOP 配置方式。它支持使用@Aspect
註解定義切面,並且還支持其他註解如@Before
、@After
、@Around
等,用於在目標 bean 的方法上應用切面邏輯;
默認情況下,我們的項目都是基於 AnnotationAwareAspectJAutoProxyCreator
實現的 AOP 功能。
在後文,我們會深入後處理器的源碼,從而跟蹤 AOP 的運行流程。