Spring AOP 支持哪兩種動(dòng)態(tài)代理方式(最新推薦)
什么是動(dòng)態(tài)代理?
動(dòng)態(tài)代理就是,在程序運(yùn)行期,創(chuàng)建目標(biāo)對(duì)象的代理對(duì)象,并對(duì)目標(biāo)對(duì)象中的方法進(jìn)行功能性增強(qiáng)的一種技術(shù)。
在生成代理對(duì)象的過(guò)程中,目標(biāo)對(duì)象不變,代理對(duì)象中的方法是目標(biāo)對(duì)象方法的增強(qiáng)方法??梢岳斫鉃檫\(yùn)行期間,對(duì)象中方法的動(dòng)態(tài)攔截,在攔截方法的前后執(zhí)行功能操作。
Spring AOP 支持以下兩種動(dòng)態(tài)代理方式:
- JDK 動(dòng)態(tài)代理 (JDK Dynamic Proxy)
- CGLIB 代理 (Code Generation Library)
Spring 框架會(huì)根據(jù)你的業(yè)務(wù)對(duì)象(目標(biāo)對(duì)象)的情況,智能地選擇其中一種來(lái)創(chuàng)建代理。
1. JDK 動(dòng)態(tài)代理
- 技術(shù)基礎(chǔ):Java 官方提供的
java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口,是 Java 原生支持的。 - 實(shí)現(xiàn)方式:在運(yùn)行時(shí),創(chuàng)建一個(gè)新的代理類,這個(gè)代理類會(huì)實(shí)現(xiàn)目標(biāo)對(duì)象所實(shí)現(xiàn)的所有接口。
- 硬性要求:被代理的目標(biāo)對(duì)象必須實(shí)現(xiàn)至少一個(gè)接口。 如果一個(gè)類沒(méi)有實(shí)現(xiàn)任何接口,JDK 動(dòng)態(tài)代理就無(wú)法為其創(chuàng)建代理。
- 工作流程:當(dāng)你調(diào)用代理對(duì)象的方法時(shí),這個(gè)調(diào)用會(huì)被轉(zhuǎn)發(fā)到
InvocationHandler的invoke()方法中。Spring AOP 在invoke()方法內(nèi)部織入了你的切面邏輯(如@Before、@After等),然后再通過(guò) Java 的反射機(jī)制調(diào)用原始目標(biāo)對(duì)象的方法。
2. CGLIB 代理
- 技術(shù)基礎(chǔ):一個(gè)強(qiáng)大的第三方代碼生成庫(kù)(Spring 內(nèi)部集成了它),它通過(guò)字節(jié)碼增強(qiáng) (Bytecode Enhancement) 技術(shù)來(lái)工作。
- 實(shí)現(xiàn)方式:在運(yùn)行時(shí),動(dòng)態(tài)地創(chuàng)建一個(gè)被代理對(duì)象的子類作為代理對(duì)象。
- 硬性要求:被代理的目標(biāo)類不能是
final類,需要被代理的方法也不能是final或private,因?yàn)樽宇悷o(wú)法繼承final類或重寫final/private方法。 - 工作流程:代理類會(huì)重寫(Override)父類(即你的目標(biāo)對(duì)象)中所有非
final的方法。在這些重寫的方法里,Spring AOP 織入了切面邏輯,然后再通過(guò)調(diào)用super.method()來(lái)執(zhí)行原始目標(biāo)對(duì)象的業(yè)務(wù)邏輯。
Spring 如何選擇?
這是面試中的高頻問(wèn)題,因?yàn)檫@個(gè)默認(rèn)行為在不同版本中有所變化。
| 場(chǎng)景 | Spring 的選擇 |
|---|---|
| 目標(biāo)對(duì)象實(shí)現(xiàn)了接口 | 在老的 Spring 版本或傳統(tǒng) Spring XML 配置中,默認(rèn)使用 JDK 動(dòng)態(tài)代理。 在Spring Boot (2.x 及以后) 中,為了統(tǒng)一行為和解決一些代理問(wèn)題,默認(rèn)依然使用 CGLIB。 |
| 目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口 | 無(wú)論在哪個(gè)版本,都只能使用 CGLIB。 |
為什么 Spring Boot 默認(rèn)使用 CGLIB?
主要原因是為了解決“方法自調(diào)用時(shí) AOP 失效”的問(wèn)題,并提供更一致的行為。使用 CGLIB 可以確保即使目標(biāo)對(duì)象實(shí)現(xiàn)了接口,代理的也是類本身,這在處理一些復(fù)雜的依賴注入和內(nèi)部調(diào)用場(chǎng)景時(shí)更加可靠。
當(dāng)然,你也可以通過(guò)在 application.properties 中進(jìn)行配置來(lái)改變這個(gè)默認(rèn)行為:
# 如果設(shè)置為 true (默認(rèn)值),則統(tǒng)一使用 CGLIB # 如果設(shè)置為 false,則在目標(biāo)對(duì)象實(shí)現(xiàn)接口時(shí),會(huì)優(yōu)先使用 JDK 動(dòng)態(tài)代理 spring.aop.proxy-target-class=true
總結(jié)對(duì)比
| 特性 | JDK 動(dòng)態(tài)代理 | CGLIB 代理 |
|---|---|---|
| 代理方式 | 基于接口 (實(shí)現(xiàn)共同接口) | 基于繼承 (創(chuàng)建子類) |
| 前提條件 | 目標(biāo)對(duì)象必須實(shí)現(xiàn)接口 | 目標(biāo)對(duì)象不能是 final 類 |
| 性能 | 在早期版本中,通過(guò)反射調(diào)用性能略低于 CGLIB。但在目前JDK 版本中,兩者性能差距已經(jīng)非常小。 | 性能通常被認(rèn)為略高,因?yàn)樗苯硬僮髯止?jié)碼并調(diào)用 super。 |
| Spring Boot 默認(rèn) | 否 | 是 |
到此這篇關(guān)于Spring AOP 支持哪兩種動(dòng)態(tài)代理方式?的文章就介紹到這了,更多相關(guān)spring aop動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
強(qiáng)烈推薦 5 款好用的REST API工具(收藏)
市面上可用的 REST API 工具選項(xiàng)有很多,我們來(lái)看看其中一些開發(fā)人員最喜歡的工具。本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2020-12-12
java構(gòu)建Stream流的多種方式總結(jié)
Java?8引入了Stream流作為一項(xiàng)新的特性,它是用來(lái)處理集合數(shù)據(jù)的一種函數(shù)式編程方式,本文為大家整理了多種java構(gòu)建Stream流的方式,希望對(duì)大家有所幫助2023-11-11
Spring boot調(diào)用Oracle存儲(chǔ)過(guò)程的兩種方式及完整代碼
這篇文章主要給大家介紹了關(guān)于Spring boot調(diào)用Oracle存儲(chǔ)過(guò)程的兩種方式及完整代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Mybatis pagehelper分頁(yè)插件使用過(guò)程解析
這篇文章主要介紹了mybatis pagehelper分頁(yè)插件使用過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
java實(shí)現(xiàn)網(wǎng)頁(yè)驗(yàn)證碼功能
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)網(wǎng)頁(yè)驗(yàn)證碼功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Spring?Security?過(guò)濾器注冊(cè)脈絡(luò)梳理
這篇文章主要介紹了Spring?Security過(guò)濾器注冊(cè)脈絡(luò)梳理,Spring?Security在Servlet的過(guò)濾鏈中注冊(cè)了一個(gè)過(guò)濾器FilterChainProxy,它會(huì)把請(qǐng)求代理到Spring?Security自己維護(hù)的多個(gè)過(guò)濾鏈,每個(gè)過(guò)濾鏈會(huì)匹配一些URL,如果匹配則執(zhí)行對(duì)應(yīng)的過(guò)濾器2022-08-08
淺談java多線程 join方法以及優(yōu)先級(jí)方法
下面小編就為大家?guī)?lái)一篇淺談java多線程 join方法以及優(yōu)先級(jí)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
Spring事務(wù)失效之常見(jiàn)場(chǎng)景分析
這篇文章主要介紹了Spring事務(wù)失效之常見(jiàn)場(chǎng)景,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04

