該系列文章是本人在學習 Spring 的程序中總結下來的,里面涉及到相關原始碼,可能對讀者不太友好,請結合我的原始碼注釋 Spring 原始碼分析 GitHub 地址 進行閱讀,
Spring 版本:5.1.14.RELEASE
在開始閱讀 Spring AOP 原始碼之前,需要對 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章導讀》 這一系列文章
了解 AOP 相關術語,可先查看 《Spring AOP 常見面試題) 》 這篇文章
該系列其他文章請查看:《死磕 Spring 之 AOP 篇 - 文章導讀》
通過上一篇 《初識 JDK、CGLIB 兩種動態代理》 文章我們對 Spring AOP 底層的 JDK 動態代理和 CGLIB 動態代理有了一定的了解,也知道如何簡單地使用兩種動態代理創建代理物件,相信上篇文章可以讓你對 Spring AOP 有了一個初步的認識,那么接下來我們準備進入 Spring AOP 原始碼學習階段,
在開始 Spring AOP 原始碼學習前,本文會對 Spring AOP 涉及到的大部分主要的 API 進行介紹,讓我們對 Spring AOP 有一個全面的認識,這樣在學習 Spring AOP 原始碼的程序中有一個清晰的思路會更加易于理解,然后在后續的文章從 Spring AOP 的自動代理開始深入學習,直接進入正題吧,
Spring AOP API 總覽
如下圖所示:
上面這張圖片列出了 Spring AOP 涉及到的大部分 API,接下來我們依次簡單介紹一下:
-
Joinpoint:連接點,也就是我們需要執行的目標方法
-
Pointcut:切點,提供 ClassFilter 類過濾器和 MethodMatcher 方法匹配器支持對類和方法進行篩選,
-
Advice:通知器,一般都是 MethodInterceptor 方法攔截器,不是的話會通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,
-
Advisor:Advice 容器介面,與 Advice 是一對一的關系;它的子介面 PointcutAdvisor 相當于一種 Pointcut 和 Advice 的容器,將 Pointcut 過濾 Joinpoint 的能力和 Advice 進行整合,這樣一來就將兩者關聯起來了,
-
Advisor 配接器:AdvisorAdapter 是 Advisor 的配接器,當篩選出能夠應用于方法的所有 Advisor 后,需要獲取對應的 Advice;
- 如果不是 MethodInterceptor 型別,則需要通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,
-
AOP 代理物件:AOP 代理物件,由 JDK 動態代理或者 CGLIB 動態代理創建的代理物件;
- 選擇哪種動態代理是通過 AopProxyFactory 代理工廠根據目標類來決定的,
-
AOP 代理配置:AdvisedSupport 配置管理器中保存了對應代理物件的配置資訊,例如滿足條件的 Advisor 物件、TargetSource 目標類來源;
- 在創建代理物件的程序,AdvisedSupport 扮演著一個非常重要的角色,
-
AOP 代理物件創建:AOP 代理物件的創建分為手動模式和自動模式;不管哪種模式都和 AdvisedSupport 配置管理器有關;
- 手動模式就是通過 Spring AOP 提供的 API 進行創建;
- 自動模式則是和 Spring IoC 進行整合,在 Bean 的加載程序中如果需要進行代理,則創建對應的代理物件;
-
AdvisorChainFactory:Advisor 鏈路工廠
- AdvisedSupport 配置管理器中保存了代理物件的所有 Advisor 物件,當攔截某個方法時,需要通過 AdvisorChainFactory 篩選出能夠應用于該方法的 Advisor 們;
- 另外還需要借助 AdvisorAdapter 配接器獲取 Advisor 對應的 MethodInterceptor 方法攔截器,將這些 MethodInterceptor 有序地形成一條鏈路并回傳,
-
IntroductionInfo:引介介面,支持代理物件實作目標類沒有真正實作的額外的介面;
- 在 Advisor 的子介面 IntroductionAdvisor 中會繼承這個 IntroductionInfo 介面,通過 @DeclareParents 注解定義的欄位會被決議成 IntroductionAdvisor 物件,
-
AOP 代理目標物件來源:目標類來源,和代理物件進行關聯,用于獲取被代理代理的目標物件;
- 在代理物件中最終的方法執行都需要先通過 TargetSource 獲取對應的目標物件,然后執行目標方法,
Joinpoint
類圖
-
ConstructorInvocation,是基于構造器的一個呼叫器,在 Spring AOP 中僅支持方法級別的代理,所以這個介面并沒有被使用
-
ReflectiveMethodInvocation,Joinpoint 的底層實作類,一個基于反射的方法呼叫器,本文不進行分析,在后續的文章進行講解??
-
CglibMethodInvocation,和上者實作類差不多,新增了一個 CGLIB 中的 MethodProxy 方法代理物件,本文不進行分析,在后續的文章進行講解??
org.aopalliance.intercept.Joinpoint,連接點,也就是我們需要執行的目標方法,是由 AOP 聯盟提供的一個介面,如下:
public interface Joinpoint {
/**
* 執行方法呼叫器中的下一個攔截器,執行完所有的攔截器則執行目標方法
*/
Object proceed() throws Throwable;
/**
* 回傳目標物件
*/
Object getThis();
/**
* 回傳目標方法
*/
AccessibleObject getStaticPart();
}
org.aopalliance.intercept.Invocation,呼叫器,是由 AOP 聯盟提供的一個介面,如下:
public interface Invocation extends Joinpoint {
/**
* 獲取引數陣列
*/
Object[] getArguments();
}
MethodInvocation
org.aopalliance.intercept.MethodInvocation,方法呼叫器,是由 AOP 聯盟提供的一個介面,如下:
public interface MethodInvocation extends Invocation {
/**
* 獲取目標方法
*/
Method getMethod();
}
ProxyMethodInvocation
org.springframework.aop.ProxyMethodInvocation,MethodInvocation 方法呼叫器的擴展,允許訪問代理物件,如下:
public interface ProxyMethodInvocation extends MethodInvocation {
/**
* 回傳代理物件
*/
Object getProxy();
/**
* 克隆方法
*/
MethodInvocation invocableClone();
/**
* 克隆方法,使用引數
*/
MethodInvocation invocableClone(Object... arguments);
/**
* 設定引數陣列
*/
void setArguments(Object... arguments);
/**
* 添加自定義屬性
*/
void setUserAttribute(String key, @Nullable Object value);
/**
* 獲取自定義屬性
*/
@Nullable
Object getUserAttribute(String key);
}
Pointcut
類圖
- AspectJExpressionPointcut,基于 AspectJ 處理運算式的能力實作的一個 Pointcut,本文不進行分析,在后續的文章進行講解??
上述類圖僅列出了部分 Pointcut 相關的介面
org.springframework.aop.Pointcut,切點,提供 ClassFilter 類過濾器和 MethodMatcher 方法匹配器支持對類和方法進行篩選,如下:
public interface Pointcut {
/**
* 回傳類過濾器
*/
ClassFilter getClassFilter();
/**
* 回傳方法匹配器
*/
MethodMatcher getMethodMatcher();
/**
* 總是匹配通過的 Pointcut 實體物件
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
org.springframework.aop.support.ExpressionPointcut,支持運算式匹配的 Pointcut,如下:
public interface ExpressionPointcut extends Pointcut {
/**
* 回傳運算式
*/
@Nullable
String getExpression();
}
StaticMethodMatcherPointcut
org.springframework.aop.support.StaticMethodMatcherPointcut,抽象類,本身是一個方法匹配器的 Pointcut,如下:
public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
/** 默認情況類過濾器總是匹配通過 */
private ClassFilter classFilter = ClassFilter.TRUE;
/**
* 設定類過濾器
*/
public void setClassFilter(ClassFilter classFilter) {
this.classFilter = classFilter;
}
/**
* 獲取類過濾器
*/
@Override
public ClassFilter getClassFilter() {
return this.classFilter;
}
/**
* 回傳方法匹配器,就是當前物件,因為當前物件繼承的 StaticMethodMatcher 就是一個 MethodMatcher
*/
@Override
public final MethodMatcher getMethodMatcher() {
return this;
}
}
我們自定義的 Pointcut 通常可以繼承 StaticMethodMatcherPointcut 來實作,重寫 MethodMatcher matches(Method method, Class<?> targetClass, Object... args) 方法即可,也可以再實作 ClassFilter,實作 matches(Class clazz) 方法
ClassFilter
org.springframework.aop.ClassFilter,函式式介面,類過濾器,用于判斷這個 Class 是否滿足 Pointcut 切點,如下:
@FunctionalInterface
public interface ClassFilter {
/**
* 匹配這個 Class 類
*/
boolean matches(Class<?> clazz);
/**
* 總是匹配通過的類過濾器
*/
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
MethodMatcher
org.springframework.aop.MethodMatcher,方法匹配器,用于判斷這個 Method 是否滿足 Pointcut 切點,如下:
public interface MethodMatcher {
/**
* 匹配這個方法
*/
boolean matches(Method method, Class<?> targetClass);
/**
* 當前方法匹配器是否為運行狀態
*/
boolean isRuntime();
/**
* 匹配這個方法,并校驗引數
*/
boolean matches(Method method, Class<?> targetClass, Object... args);
/**
* 總是匹配通過的方法匹配器
*/
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
Advice
類圖
- Advice,標記介面
- BeforeAdvice,標記介面,后置通知
- AfterAdvice,標記介面,前置通知
- Interceptor,標記介面,攔截器
- AbstractAspectJAdvice,包裝了一個 Aspect 切面或者 AspectJ 注解標注的方法,Around、Before、After、AfterReturning、AfterThrowing 幾種型別的 Advice 最終都會轉換成 AbstractAspectJAdvice 對應的子類并實作 MethodInterceptor 方法攔截器介面,本文不進行分析,在后續的文章進行講解??
上述類圖僅列出了部分 Advice 相關的介面
MethodInterceptor
org.aopalliance.intercept.MethodInterceptor,方法攔截器,函式式介面,如下:
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
/**
* 執行 MethodInvocation 呼叫器
*/
Object invoke(MethodInvocation invocation) throws Throwable;
}
Advisor
類圖
上面只列出了 Advisor 的部分實作類,在 Spring AOP 中還有非常多的實作類,在后續的文章進行分析??
- AbstractBeanFactoryPointcutAdvisor,關聯 BeanFactory 的 PointcutAdvisor 抽象類,支持從 IoC 容器中獲取 Advice 物件,我們可以通過繼承這個類來自定義一個 PointcutAdvisor 物件
org.springframework.aop.Advisor,Advice 容器介面,與 Advice 是一對一的關系,如下:
public interface Advisor {
/**
* 空的 Advice
*/
Advice EMPTY_ADVICE = new Advice() {};
/**
* 獲取 Advice
*/
Advice getAdvice();
/**
* 回傳這個 Advice 是否有一個指定的目標實體物件,默認都是 true
*/
boolean isPerInstance();
}
PointcutAdvisor
org.springframework.aop.PointcutAdvisor,繼承 Advisor 介面,Pointcut 和 Advice 的容器,將 Pointcut 過濾 Joinpoint 的能力和 Advice 進行整合,這樣一來就將兩者關聯起來了,如下:
public interface PointcutAdvisor extends Advisor {
/**
* 獲取 Pointcut 切點
*/
Pointcut getPointcut();
}
IntroductionAdvisor
org.springframework.aop.IntroductionAdvisor,繼承 Advisor 和 IntroductionInfo 介面,支持代理物件實作目標類沒有真正實作的額外的介面;通過 @DeclareParents 注解定義的欄位會被決議成 IntroductionAdvisor 物件,如下:
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
/**
* 獲取類加載器,因為沒有 Pointcut 切點,則提供一個類過濾器
*/
ClassFilter getClassFilter();
/**
* 校驗是否實作 IntroductionInfo 中的介面
*/
void validateInterfaces() throws IllegalArgumentException;
}
public interface IntroductionInfo {
/**
* 回傳額外的介面
*/
Class<?>[] getInterfaces();
}
AdvisorAdapter
類圖
org.springframework.aop.framework.adapter.AdvisorAdapter,Advisor 的配接器,當篩選出能夠應用于方法的所有 Advisor 后,需要獲取對應的 Advice;如果不是 MethodInterceptor 型別,則需要通過 AdvisorAdapter 配接器轉換成對應的 MethodInterceptor 方法攔截器,如下:
public interface AdvisorAdapter {
/**
* 是否支持該型別的 Advice 適配
*/
boolean supportsAdvice(Advice advice);
/**
* 獲取 Advisor 的 Advice,并包裝成對應的 MethodInterceptor 方法攔截器
*/
MethodInterceptor getInterceptor(Advisor advisor);
}
org.springframework.aop.framework.adapter.MethodBeforeAdviceAdapter,前置 Advice 的配接器,如下:
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
可以看到這個 MethodBeforeAdviceAdapter 配接器只能在 Spring 內部使用,先判斷 Advice 是否為 MethodBeforeAdvice 型別,如果是的話,則可以將 Advice 包裝成 MethodBeforeAdviceInterceptor 物件,其他的配接器類似,
當然,AdvisorAdapter 配接器不是直接被使用,而是通過 DefaultAdvisorAdapterRegistry 配接器注冊中心使用的,在后續文章進行分析??
AOP 代理物件
類圖
org.springframework.aop.framework.AopProxy,AOP 代理介面,用于創建代理物件,如下:
public interface AopProxy {
/**
* 創建一個代理物件
*/
Object getProxy();
/**
* 創建一個代理物件,傳入指定的 ClassLoader 類加載器
*/
Object getProxy(@Nullable ClassLoader classLoader);
}
在 Spring AOP 中有 JdkDynamicAopProxy 和 CglibAopProxy 兩種實作類,分別代表 JDK 動態代理和 CGLIB 動態代理,選擇哪種動態代理是通過 DefaultAopProxyFactory 代理工廠根據目標類來決定的,這些內容在后續文章進行分析??
AOP 代理配置
類圖
org.springframework.aop.framework.ProxyConfig,代理配置類,如下:
/**
* @see AdvisedSupport
*/
public class ProxyConfig implements Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = -8409359707199703185L;
/** 是否使用類代理 */
private boolean proxyTargetClass = false;
private boolean optimize = false;
boolean opaque = false;
/** 是否暴露代理物件 */
boolean exposeProxy = false;
/** 配置是否被凍結 */
private boolean frozen = false;
}
這個類僅提供一些頂層的配置資訊,更多和創建代理物件相關的配置資訊都在子類 AdvisedSupport 中,這些內容在后續文章進行分析??
AOP 代理物件創建
類圖
AOP 代理物件的創建分為手動模式和自動模式;不管哪種模式都和 AdvisedSupport 配置管理器有關;
- 手動模式就是通過 Spring AOP 提供的 API 進行創建,例如 ProxyFactory 代理工廠;
- 自動模式則是和 Spring IoC 進行整合,在 Bean 的加載程序中如果需要進行代理,則創建對應的代理物件;可以看到 AbstractAutoProxyCreator 實作了 BeanPostProcessor 相關介面,在加載 Bean 的程序中,初始化后會呼叫 BeanPostProcessor#postProcessAfterInitialization 的初始化后置處理方法,在 AbstractAutoProxyCreator 中則可以創建對應的代理物件(如果有必要的話)
上面這些 AOP 自動代理類在后續文章會進行分析??
AOP 代理目標物件來源
類圖
org.springframework.aop.TargetSource,目標類來源,和代理物件進行關聯,用于獲取被代理代理的目標物件,如下:
public interface TargetSource extends TargetClassAware {
/**
* 獲取目標物件的 Class 物件
*/
@Override
@Nullable
Class<?> getTargetClass();
/**
* 是否是靜態的,回傳 `fasle` 表示每次獲取目標物件都需要進行創建,那么每次創建都需要釋放,例如原型模式的 Bean
*/
boolean isStatic();
/**
* 獲取目標物件
*/
@Nullable
Object getTarget() throws Exception;
/**
* 釋放目標物件
*/
void releaseTarget(Object target) throws Exception;
}
SingletonTargetSource
org.springframework.aop.target.SingletonTargetSource,單例 Bean 的目標物件來源,如下:
public class SingletonTargetSource implements TargetSource, Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 9031246629662423738L;
/** 保存目標物件 */
private final Object target;
/**
* 創建實體物件的時候就是設定目標物件
*/
public SingletonTargetSource(Object target) {
Assert.notNull(target, "Target object must not be null");
this.target = target;
}
@Override
public Class<?> getTargetClass() {
return this.target.getClass();
}
@Override
public Object getTarget() {
return this.target;
}
@Override
public void releaseTarget(Object target) {
// nothing to do
}
@Override
public boolean isStatic() {
return true;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof SingletonTargetSource)) {
return false;
}
SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
return this.target.equals(otherTargetSource.target);
}
@Override
public int hashCode() {
return this.target.hashCode();
}
@Override
public String toString() {
return "SingletonTargetSource for target object [" + ObjectUtils.identityToString(this.target) + "]";
}
}
單例 Bean 對應的 TargetSource 都是 SingletonTargetSource,里面保存了這個單例 Bean,
總結
本文開頭的圖片展示了 Spring AOP 涉及到的大部分主要的 API,圍繞著這張圖片對這些 API 進行簡單的講述,對 Spring AOP 可以有一個整體的認識,不過 Spring AOP 還有一個部分,如何開啟整個 AOP 模塊在本文沒有體現出來,簡單提一下,通過 @EnableAspectJAutoProxy 注解或者 <aop:aspectj-autoproxy /> XML 配置可以激活 AOP 模塊,底層會注冊一個 AbstractAutoProxyCreator 型別的 Bean 完成 AOP 自動代理,具體程序在后面的文章進行分析??
-
在 Spring AOP 中有著
Joinpoint連接點,Pointcut切點和Advice通知,通過Advisor介面保存一個Advice,其子介面PointcutAdvisor又關聯一個Pointcut,將Pointcut過濾Joinpoint的能力和Advice進行整合,這樣一來就將兩者關聯起來了, -
Spring AOP 傳遞
Advice的程序通常是通過Advisor實作的,而使用Advice的程序都是通過MethodInterceptor執行,如果不是該型別則通過AdvisorAdapter配接器將其包裝成對應的MethodInterceptor方法攔截器, -
Sping AOP 底層有 JDK 動態代理和 CGLIB 動態代理兩種方式,分別對應
JdkDynamicAopProxy和CglibAopProxy,選擇哪種代理方式需要通過DefaultAopProxyFactory代理工廠根據目標類來決定, -
在 Spring AOP 中一個
AdvisedSupport配置管理器,里面保存對應代理物件的配置資訊,例如滿足條件的Advisor物件、TargetSource目標類來源,AdvisedSupport在 Spring AOP 中扮演一個重要的角色, -
Spring AOP 中的自動代理主要由
AbstractAutoProxyCreator這個 Bean 進行創建,因為它實作了幾種BeanPostProcessor,例如在 Bean 加載程序中,初始化后會呼叫AbstractAutoProxyCreator的方法進行處理,回傳一個代理物件(如果有必要的話),
在后續的文章我們主要圍繞自動代理進行分析,對于 Bean 的加載程序不熟悉的小伙伴可查看我前面的《死磕Spring之IoC篇 - 文章導讀》文章,或者直接查看《死磕Spring之IoC篇 - Bean 的創建程序》 這篇文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/276917.html
標籤:其他
