SpringAOP中JDK和CGLib動態代理哪個更快?

java填坑路發表於2018-09-11

一、背景

昨天一位小夥伴面試的時候被問到:Spring AOP中JDK和CGLib動態代理哪個效率更高?整理了一下,今天特分享出來,供大家參考!

二、基本概念

首先,我們知道Spring AOP的底層實現有兩種方式:一種是JDK動態代理,另一種是CGLib的方式。

自Java 1.3以後,Java提供了動態代理技術,允許開發者在執行期建立介面的代理例項,後來這項技術被用到了Spring的很多地方。

JDK動態代理主要涉及java.lang.reflect包下邊的兩個類:Proxy和InvocationHandler。其中,InvocationHandler是一個介面,可以通過實現該介面定義橫切邏輯,並通過反射機制呼叫目標類的程式碼,動態地將橫切邏輯和業務邏輯編織在一起。

JDK動態代理的話,他有一個限制,就是它只能為介面建立代理例項,而對於沒有通過介面定義業務方法的類,如何建立動態代理例項哪?答案就是CGLib。

CGLib採用底層的位元組碼技術,全稱是:Code Generation Library,CGLib可以為一個類建立一個子類,在子類中採用方法攔截的技術攔截所有父類方法的呼叫並順勢織入橫切邏輯。

三、JDK 和 CGLib動態代理區別

1、JDK動態代理具體實現原理:

通過實現InvocationHandler介面建立自己的呼叫處理器;

通過為Proxy類指定ClassLoader物件和一組interface來建立動態代理;

通過反射機制獲取動態代理類的建構函式,其唯一引數型別就是呼叫處理器介面型別;

通過建構函式建立動態代理類例項,構造時呼叫處理器物件作為引數參入;

JDK動態代理是面向介面的代理模式,如果被代理目標沒有介面那麼Spring也無能為力,Spring通過Java的反射機制生產被代理介面的新的匿名實現類,重寫了其中AOP的增強方法。

2、CGLib動態代理:

CGLib是一個強大、高效能的Code生產類庫,可以實現執行期動態擴充套件java類,Spring在執行期間通過 CGlib繼承要被動態代理的類,重寫父類的方法,實現AOP面向切面程式設計呢。

3、兩者對比:

JDK動態代理是面向介面的。

CGLib動態代理是通過位元組碼底層繼承要代理類來實現(如果被代理類被final關鍵字所修飾,那麼抱歉會失敗)。

4、使用注意:

如果要被代理的物件是個實現類,那麼Spring會使用JDK動態代理來完成操作(Spirng預設採用JDK動態代理實現機制);

如果要被代理的物件不是個實現類那麼,Spring會強制使用CGLib來實現動態代理。

四、JDK 和 CGLib動態代理效能對比-教科書上的描述

我們不管是看書還是看文章亦或是我那個上搜尋參考答案,可能很多時候,都可以找到如下的回答:

關於兩者之間的效能的話,JDK動態代理所建立的代理物件,在以前的JDK版本中,效能並不是很高,雖然在高版本中JDK動態代理物件的效能得到了很大的提升,但是他也並不是適用於所有的場景。主要體現在如下的兩個指標中:

1、CGLib所建立的動態代理物件在實際執行時候的效能要比JDK動態代理高不少,有研究表明,大概要高10倍;

2、但是CGLib在建立物件的時候所花費的時間卻比JDK動態代理要多很多,有研究表明,大概有8倍的差距;

3、因此,對於singleton的代理物件或者具有例項池的代理,因為無需頻繁的建立代理物件,所以比較適合採用CGLib動態代理,反正,則比較適用JDK動態代理。

結果是不是如上邊1、2、3條描述的那樣哪?下邊我們做一些小實驗分析一下!

五、效能測試

1、首先有幾個Java類

2、Target.java

3、TargetImpl.java

4、JdkDynamicProxyTest.java

5、CglibProxyTest.java

6、ProxyPerformanceTest.java

7、測試結果

(1)JDK 1.6

(2)JDK 1.7

(3)JDK 1.8

經過多次試驗,可以看出平均情況下的話,JDK動態代理的執行速度已經逐漸提高了,在低版本的時候,執行的效能可能不如CGLib,但是在1.8版本中執行多次,基本都可以得到一致的測試結果,那就是JDK動態代理已經比CGLib動態代理快了!

但是JDK動態代理和CGLib動態代理的適用場景還是不一樣的哈!

六、總結

最終的測試結果大致是這樣的,在1.6和1.7的時候,JDK動態代理的速度要比CGLib動態代理的速度要慢,但是並沒有教科書上的10倍差距,在JDK1.8的時候,JDK動態代理的速度已經比CGLib動態代理的速度快很多了,希望小夥伴在遇到這個問題的時候能夠有的放矢!

Spring AOP中的JDK和CGLib動態代理關於這個知識點很重要,關於兩者之間效能的對比經過測試實驗已經有了一個初步的結果,以後再有人問你Spring AOP,不要簡單的說JDK動態代理和CGLib這兩個了,是時候的可以丟擲來對兩者之間區別的理解,是有加分的哦!

歡迎工作一到五年的Java工程師朋友們加入Java架構開發:744677563

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用”沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!


相關文章