上一篇SpringAOP專欄一《使用教程篇》-CSDN博客介紹了SpringAop如何使用,這一篇文章就會介紹Spring AOP 的底層實現原理,并通過源代碼解析來詳細闡述其實現過程。
前言
Spring AOP 的實現原理是基于動態代理和字節碼操作的。不了解動態代理和字節碼操作的讀者可以先看一下這篇文章java中的反射和代理模式-CSDN博客
實現原理
下面我會基于在使用SpringAOP進行邏輯增強時各個核心類的執行順序進行底層原理的剖析
實現代理和切面邏輯的核心類執行順序如下:
1.Bean 實例化階段:
- BeanPostProcessor:在 Bean 實例化之后,進行初始化前的處理。其中,AbstractAutoProxyCreator 是一個重要的 BeanPostProcessor 實現類,用于自動創建代理對象。
2.切面織入階段:
- AdvisedSupport:封裝了切面邏輯和目標對象信息。
- ProxyFactoryBean:生成代理對象的工廠類。
- AopProxyFactory:AOP 代理對象的工廠接口。
- AopProxy:AOP 代理對象的核心接口,定義了獲取代理對象的方法。
- CglibAopProxy:基于 CGLIB 的動態代理實現類。
- DynamicAdvisedInterceptor:CGLIB 動態代理的回調函數實現類,用于觸發切面邏輯的執行。
3.方法攔截與執行階段:
- ProxyMethodInvocation:代理方法調用的核心類,封裝了目標對象方法和參數信息。
- ReflectiveMethodInvocation:反射調用目標方法的類,是 ProxyMethodInvocation 的具體實現類。
- MethodInvocationInterceptor:方法攔截器接口,定義了攔截器的方法執行邏輯。
- MethodInterceptor:CGLIB 庫中的接口,被 MethodInvocationInterceptor 實現。
Bean 實例化階段
在service bean的創建過程中(也就是getBean("service")
),AOP通過BeanPostProcess
后置處理器操作進行介入 分為2種情況:
- 用戶自定義了
targetSource
,則bean的創建(實例化、填充、初始化)均由用戶負責,Spring Ioc不會在管該代理目標對象traget,這種情況基本上不會發生,很多人用了幾年Spring可能都不知道有它的存在- 正常情況下都是Spring Ioc完成代理對象target的實例化、填充、初始化。然后在初始化后置處理器中進行介入,對bean也就是service進行代理
下面是Bean示例化的流程圖
切面織入階段
Spring AOP 是構建在動態代理基礎上,因此?Spring 對 AOP 的支持局限于方法級別的攔截。
在這個階段會讀取相關的SpringAOP的配置,如何將切面邏輯和目標對象信息封裝到AdvisedSupport中,再通過ProxyFactoryBean(生成代理對象的工廠類)根據目標對象是否實現接口來調用JDK動態代理還是Cglib代理。
下面詳細介紹一下兩者代理方式的實現源碼:
Spring AOP 動態代理實現:
- 默認情況下,實現了接?的類,使? AOP 會基于 JDK ?成代理類,沒有實現接?的類,會基于 CGLIB ?成代理類。
- JDK Proxy(JDK 動態代理)
- CGLIB Proxy:默認情況下 Spring AOP 都會采用 CGLIB 來實現動態代理,因為效率高
- CGLIB 實現原理:通過繼承代理對象來實現動態代理的(子類擁有父類的所有功能)
- CGLIB 缺點:不能代理最終類(也就是被 final 修飾的類)
?
JDK動態代理
????JDK 動態代理是 Java 自帶的動態代理實現方式。使用JDK動態代理時,需要目標對象實現至少一個接口。JDK 動態代理會在運行時生成一個實現了目標對象接口的代理類,該代理類會在目標對象方法執行前后插入切面代碼。
下面是JdkDynamicAopProxy類的部分源碼,感興趣的讀者可以自己去看看,我這里就不一一截圖給大家看了。
如果讀者看源碼如果有困難,可以看一下這個我簡化了的JdkDynamicAopProxy類。這個類我保留了主要邏輯,把一些提高代碼健壯性的部分去掉了。
JdkDynamicAopProxy 類的主要作用是將切面邏輯織入到目標對象的方法調用中。當使用基于接口的代理方式時,Spring AOP 使用 JDK 動態代理來創建代理對象。JdkDynamicAopProxy 類會根據配置的切面信息,動態地生成一個代理對象,并將切面邏輯織入到該代理對象的方法調用中。
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {private final AdvisedSupport advised;public JdkDynamicAopProxy(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object getProxy() {return Proxy.newProxyInstance(getClass().getClassLoader(),advised.getTargetSource().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInterceptor methodInterceptor = advised.getMethodInterceptor();MethodInvocation methodInvocation = new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(),method,args,methodInterceptor,advised.getTargetSource().getTargetClass());return methodInvocation.proceed();}
}
??在該代碼中,JdkDynamicAopProxy 類實現了 AopProxy 和 InvocationHandler 接口。
AopProxy 接口是 Spring AOP 提供的代理接口,它定義了獲取代理對象的方法。JdkDynamicAopProxy 類通過實現該接口,提供了基于 JDK 動態代理的代理對象獲取功能。
InvocationHandler 接口是 JDK 提供的反射 API 中的一部分,它定義了一個 invoke 方法,用于在代理對象上調用被代理方法。JdkDynamicAopProxy 類實現了 InvocationHandler 接口,通過重寫 invoke 方法,實現對被代理方法的增強邏輯。
下面是對簡化了的JdkDynamicAopProxy類的詳細解讀
AdvisedSupport
類型的屬性advised
:表示該代理對象所依賴的AdvisedSupport
對象,該對象包含了切面配置信息。構造函數
JdkDynamicAopProxy(AdvisedSupport advised)
:接收一個AdvisedSupport
對象作為參數,并將其賦值給advised
屬性。
getProxy()
方法:實現了AopProxy
接口中的方法,用于獲取代理對象。它通過調用Proxy.newProxyInstance()
方法創建代理對象。
getClass().getClassLoader()
?獲取當前類的類加載器。advised.getTargetSource().getInterfaces()
?獲取目標對象實現的接口數組。this
?表示使用當前對象作為代理對象的?InvocationHandler
。
invoke(Object proxy, Method method, Object[] args)
方法:實現了InvocationHandler
接口中的方法,攔截目標對象方法的調用并進行增強邏輯。
- 首先,從?
advised
?對象中獲取?MethodInterceptor
?實例,即切面邏輯。- 然后,創建一個?
ReflectiveMethodInvocation
?實例,傳入目標對象、目標方法、方法參數、切面邏輯和目標對象的類信息。- 最后,調用?
methodInvocation.proceed()
?方法執行切面邏輯,并返回方法的執行結果。
CGLIB 代理
????????CGLIB 代理是一個基于字節碼操作的代理方式,它可以為沒有實現接口的類創建代理對象。CGLIB 代理會在運行時生成一個目標對象的子類,并覆蓋其中的方法,以實現AOP的功能。
下面是CglibAopProxy類的部分源代碼,感興趣的讀者可以自己去看看,我這里就不一一截圖給大家看了。
如果讀者看源碼如果有困難,可以看一下這個我簡化了的CglibAopProxy類。這個類我保留了主要邏輯,對代碼進行了簡化。
public class CglibAopProxy implements AopProxy {private final AdvisedSupport advised;public CglibAopProxy(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object getProxy() {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(advised.getTargetSource().getTargetClass());enhancer.setCallback(new DynamicAdvisedInterceptor(advised));return enhancer.create();}private static class DynamicAdvisedInterceptor implements MethodInterceptor {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {MethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(),method,args,proxy,advised.getMethodInterceptor(),advised.getTargetSource().getTargetClass());return methodInvocation.proceed();}}
}
CglibAopProxy 類主要有以下作用
生成代理對象:CglibAopProxy 根據目標對象和切面邏輯生成一個代理對象。與 JDK 動態代理不同,CGLIB 代理不需要目標對象實現接口。
增強方法邏輯:通過繼承目標對象,CglibAopProxy 重寫目標對象的方法,并在方法中添加切面邏輯。這樣,在調用代理對象的方法時,會先執行切面邏輯,然后再調用目標對象的原始方法。
攔截方法調用:CglibAopProxy 使用 MethodInterceptor 接口來定義切面邏輯,并將其應用于生成的代理對象。在代理對象的方法調用過程中,切面邏輯會被觸發,從而實現橫切關注點的功能,如事務管理、日志記錄等。
高性能的代理:相較于 JDK 動態代理,CGLIB 代理使用了字節碼生成技術,生成的代理對象是目標對象的子類。這種方式避免了通過反射調用目標對象的方法,提供了更高的執行性能。
下面是CglibAopProxy類的詳細解讀
CglibAopProxy 類實現了 AopProxy 接口,該接口定義了獲取代理對象的方法 getProxy()。
CglibAopProxy 類的構造方法需要一個 AdvisedSupport 對象作為參數,AdvisedSupport 是 Spring AOP 框架中的核心類,用于保存切面邏輯和目標對象信息。
getProxy() 方法中,首先實例化了 Enhancer 對象,Enhancer 是 CGLIB 庫中的主要類,用于生成代理對象。
setSuperclass() 方法將目標對象的類設置為要生成的代理類的父類,這樣代理類就可以繼承目標類的所有非私有方法。
setCallback() 方法用于設置代理類的回調函數,即在代理類的方法調用時,會觸發回調函數中的邏輯。
DynamicAdvisedInterceptor 類實現了 MethodInterceptor 接口,這個接口是 CGLIB 庫中的接口,用于定義代理類的回調函數。
intercept() 方法是 DynamicAdvisedInterceptor 類的核心方法。當代理類的方法被調用時,intercept() 方法會被觸發。在該方法中,首先將目標對象的方法和參數封裝成 MethodInvocation 對象,然后調用其 proceed() 方法,從而觸發切面邏輯的執行。
CglibMethodInvocation 類是 MethodInvocation 接口的實現類,用于封裝目標對象的方法和參數信息。
方法攔截與執行階段
該階段的實際執行流程為:
當代理對象的方法被調用時,會創建一個 ProxyMethodInvocation 對象,并將目標對象、目標方法、方法參數等信息傳遞給它。
ProxyMethodInvocation 繼承了 ReflectiveMethodInvocation 類,因此它可以通過反射調用目標方法。
在攔截器鏈的創建過程中,AdvisorChainFactory 會根據切點和通知創建 Advisor 鏈,即將所有與目標方法匹配的切面的方法攔截器添加到攔截器鏈中。
當 ProxyMethodInvocation 執行目標方法時,它會依次遍歷攔截器鏈中的每個方法攔截器。
每個方法攔截器在方法調用前后執行自己的邏輯,可以實現前置通知、后置通知、異常處理和返回通知等功能。
方法攔截器的執行順序與它們在攔截器鏈中的順序一致。在方法調用之前,攔截器依次執行前置通知;在方法調用之后,攔截器依次執行后置通知;如果方法發生異常,攔截器執行異常處理邏輯;最后,攔截器執行返回通知。
下面我來分析一下SpringAOP的攔截器
SpringAOP的攔截器
我們先來了解一下攔截器的執行屬性:如下圖所示
接下來看一下AOP攔截器執行原理,攔截器是如何保證不同通知注解下的方法的執行順序的呢?
在 Spring AOP 中,攔截器鏈的執行順序是由 AdvisedSupport 類中的方法獲取的。AdvisedSupport 包含了代理對象需要的所有信息,包括目標對象、代理接口、攔截器等。其中,攔截器鏈的創建和執行是在 ExposeInvocationInterceptor 這個攔截器中完成的。
在創建攔截器鏈時,AdvisorChainFactory 會根據切面的順序將各個切面的攔截器順序組合成一個攔截器鏈。
這樣就可以保證 before 在 after 之前執行,因為在創建攔截器鏈的過程中,會按照切面的順序將各個切面的攔截器依次添加到鏈中,最終形成一個有序的攔截器鏈。
另外,對于同一個方法的多個切面,Spring AOP 會根據切面的順序將它們的攔截器依次添加到攔截器鏈中,從而保證了它們的執行順序。這樣就可以保證 find 方法的執行順序符合切面的定義順序。
因此,通過 Spring AOP 框架內部對攔截器鏈的創建和執行機制的設計,可以保證攔截器的執行順序滿足業務需求,確保了 before 在 after 之前執行,并且保證了多個攔截器的執行順序。