Java 動態代理原理圖解 (附:2種實現方式詳細對比)
動態代理在 Java 中有著廣泛的應用,例如:Spring AOP 面向切面編程,Hibernate 數據查詢、以及 RPC Dubbo 遠程調用等,都有非常多的實際應用@mikechen
Java 動態代理原理
按照代理的創建時期,代理類可以分為兩種:
- 靜態代理:由程式設計師創建或特定工具自動生成源程式碼,再對其編譯,在程式運行前,代理類的 .class 文件就已經存在了。
- 動態代理:在程式運行時,可以運用反射機制動態創建代理類的 .class 文件。
動態代理類與靜態代理類最主要的不同點是:代理類的位元組碼不是在程式運行前生成的,而是在程式運行時再虛擬機中程式自動創建的。
動態代理的實現方式很多。例如:JDK 自身提供的動態代理,就利用了上面提到的反射機制。除了反射,動態代理還可以通過 CGLib 來實現,而 CGLib 是基於 ASM(一個 Java 位元組碼操作框架)而非反射實現的。
簡單來說,動態代理是一種行為方式,而 反射或 ASM 只是它的一種實現手段而已。
本文我主要詳解 Java 動態代理的 2 種主流現方式:JDK 原生動態代理與 CGLib 。
JDK 原生動態代理
JDK Proxy 動態代理的實現無需引用第三方類,只需要實現 InvocationHandler 介面,重寫 invoke() 方法即可,整個實現程式碼如下所示:、
以上程式的執行結果是:
動態代理之前的業務處理。
可以看出, JDK Proxy 實現動態代理的核心是實現 Invocation 介面,我們查看 Invocation 的源碼,會發現裡面其實只有一個 invoke() 方法,源碼如下:
這是因為在動態代理中有一個重要的角色,也就是代理器,它用於統一管理被代理的對象,顯然 InvocationHandler 就是這個代理器。而 invoke() 方法,則是觸發代理的執行方法,我們通過實現 Invocation 介面來擁有動態代理的能力。
CGLib 動態代理實現
CGLIB (Code Generation Library) 是一個基於 ASM 的位元組碼生成庫,它允許我們在運行時對位元組碼進行修改、和動態生成 CGLIB 通過繼承方式實現代理。
在使用 CGLib 之前,我們要先在項目中引入 CGLib 框架,在 pom.xml 中添加如下配置:
CGLib 的實現程式碼:
以上程式的執行結果是:
方法調用前業務處理。
可以看出:
CGLib 和 JDK Proxy 的實現程式碼比較類似,都是通過實現代理器的介面,再調用某一個方法完成動態代理的。
唯一不同的是,CGLib 在初始化被代理類時,是通過 Enhancer 對象把代理對象設置為被代理類的子類,來實現動態代理的。
因此,被代理類不能被關鍵字 final 修飾,如果被 final 修飾,再使用 Enhancer 設置父類時會報錯,動態代理的構建會失敗。
JDK 動態代理與 CGLib 的區別
1. JDK 動態代理具體實現原理
- 通過實現 InvocationHandler 介面,創建自己的調用處理器;
- 通過為 Proxy 類指定 ClassLoader 對象和一組 interface ,來創建動態代理;
- 通過反射機制獲取動態代理類的構造函數,其唯一參數類型就是調用處理器介面類型;
- 通過構造函數創建動態代理類實例,構造時調用處理器對象作為參數參入。
2. CGLib 動態代理
CGLib 是一個強大、高性能的 Code 生產類庫,可以實現運行期動態擴展 java 類,Spring 在運行期間通過 CGlib 繼承要被動態代理的類,重寫父類的方法,實現 AOP 面向切面編程。
3. 兩者對比
- JDK 動態代理是面向介面的。
- CGLib 動態代理是通過位元組碼底層繼承要代理類來實現(如果被代理類被 final 關鍵字所修飾,會失敗)。
4. 性能對比
- CGLib 所創建的動態代理對象,在實際運行時候的性能要比 JDK 動態代理高不少,有研究表明,大概要高出10倍;
- CGLib 在創建對象的時候所花費的時間,比 JDK 動態代理要多很多,有研究表明,大概要高出8倍。
因此,對於 singleton 的代理對象或者具有實例池的代理,因為無需頻繁的創建代理對象,更適合採用 CGLib 動態代理,反之,則比較適用 JDK 動態代理。
以上,是關於 Java 動態代理原理、以及動態代理2 種實現方式的解析。
希望有所幫助,謝謝【關注+點贊+轉發】支援。
作者簡介
陳睿 | mikechen , 10年+大廠架構經驗,「mikechen 的互聯網架構」系列文章作者,專註於互聯網架構技術。
閱讀「mikechen 的互聯網架構」40W 字技術文章合集
Java並發 | JVM | MySQL | Spring | Redis | 分散式 | 高並發
— end —