Spring AOP 支持哪兩種動態(tài)代理方式(最新推薦)
什么是動態(tài)代理?
動態(tài)代理就是,在程序運行期,創(chuàng)建目標對象的代理對象,并對目標對象中的方法進行功能性增強的一種技術。
在生成代理對象的過程中,目標對象不變,代理對象中的方法是目標對象方法的增強方法。可以理解為運行期間,對象中方法的動態(tài)攔截,在攔截方法的前后執(zhí)行功能操作。
Spring AOP 支持以下兩種動態(tài)代理方式:
- JDK 動態(tài)代理 (JDK Dynamic Proxy)
- CGLIB 代理 (Code Generation Library)
Spring 框架會根據(jù)你的業(yè)務對象(目標對象)的情況,智能地選擇其中一種來創(chuàng)建代理。
1. JDK 動態(tài)代理
- 技術基礎:Java 官方提供的
java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口,是 Java 原生支持的。 - 實現(xiàn)方式:在運行時,創(chuàng)建一個新的代理類,這個代理類會實現(xiàn)目標對象所實現(xiàn)的所有接口。
- 硬性要求:被代理的目標對象必須實現(xiàn)至少一個接口。 如果一個類沒有實現(xiàn)任何接口,JDK 動態(tài)代理就無法為其創(chuàng)建代理。
- 工作流程:當你調用代理對象的方法時,這個調用會被轉發(fā)到
InvocationHandler的invoke()方法中。Spring AOP 在invoke()方法內部織入了你的切面邏輯(如@Before、@After等),然后再通過 Java 的反射機制調用原始目標對象的方法。
2. CGLIB 代理
- 技術基礎:一個強大的第三方代碼生成庫(Spring 內部集成了它),它通過字節(jié)碼增強 (Bytecode Enhancement) 技術來工作。
- 實現(xiàn)方式:在運行時,動態(tài)地創(chuàng)建一個被代理對象的子類作為代理對象。
- 硬性要求:被代理的目標類不能是
final類,需要被代理的方法也不能是final或private,因為子類無法繼承final類或重寫final/private方法。 - 工作流程:代理類會重寫(Override)父類(即你的目標對象)中所有非
final的方法。在這些重寫的方法里,Spring AOP 織入了切面邏輯,然后再通過調用super.method()來執(zhí)行原始目標對象的業(yè)務邏輯。
Spring 如何選擇?
這是面試中的高頻問題,因為這個默認行為在不同版本中有所變化。
| 場景 | Spring 的選擇 |
|---|---|
| 目標對象實現(xiàn)了接口 | 在老的 Spring 版本或傳統(tǒng) Spring XML 配置中,默認使用 JDK 動態(tài)代理。 在Spring Boot (2.x 及以后) 中,為了統(tǒng)一行為和解決一些代理問題,默認依然使用 CGLIB。 |
| 目標對象沒有實現(xiàn)接口 | 無論在哪個版本,都只能使用 CGLIB。 |
為什么 Spring Boot 默認使用 CGLIB?
主要原因是為了解決“方法自調用時 AOP 失效”的問題,并提供更一致的行為。使用 CGLIB 可以確保即使目標對象實現(xiàn)了接口,代理的也是類本身,這在處理一些復雜的依賴注入和內部調用場景時更加可靠。
當然,你也可以通過在 application.properties 中進行配置來改變這個默認行為:
# 如果設置為 true (默認值),則統(tǒng)一使用 CGLIB # 如果設置為 false,則在目標對象實現(xiàn)接口時,會優(yōu)先使用 JDK 動態(tài)代理 spring.aop.proxy-target-class=true
總結對比
| 特性 | JDK 動態(tài)代理 | CGLIB 代理 |
|---|---|---|
| 代理方式 | 基于接口 (實現(xiàn)共同接口) | 基于繼承 (創(chuàng)建子類) |
| 前提條件 | 目標對象必須實現(xiàn)接口 | 目標對象不能是 final 類 |
| 性能 | 在早期版本中,通過反射調用性能略低于 CGLIB。但在目前JDK 版本中,兩者性能差距已經(jīng)非常小。 | 性能通常被認為略高,因為它直接操作字節(jié)碼并調用 super。 |
| Spring Boot 默認 | 否 | 是 |
到此這篇關于Spring AOP 支持哪兩種動態(tài)代理方式?的文章就介紹到這了,更多相關spring aop動態(tài)代理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring boot調用Oracle存儲過程的兩種方式及完整代碼
這篇文章主要給大家介紹了關于Spring boot調用Oracle存儲過程的兩種方式及完整代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2020-08-08

