天天看點

JDK 與 Cglib 的使用和對比

spring aop 依靠 jdk 和 cglib 進行動态代理實作。在此對兩種實作方式的一些知識進行整理。

JDK 與 Cglib 的使用和對比

可見代理成功。

概括一下,動态代理的方式一般為:

繼承 <code>invocationhandler</code> ,重寫方法 <code>invoke</code>

執行 <code>proxy.newproxyinstance</code> 生成動态代理類

由上可以看出,proxy 成功對 iinterface 接口進行代理,但是在使用時,我們并未見到 invocationhandler 中 ​<code>​invoke​</code>​ 方法的調用,動态代理是如何執行 ​<code>​invoke​</code>​ 的呢?

采用其他資料生成的案例,以下是代理類的反編譯代碼。

首先來看看代理類的繼承關系:

JDK 與 Cglib 的使用和對比

可以看到代理類繼承了 proxy ,再來看看代理類中的方法調用,其中 ​<code>​teach()​</code>​ 是被代理接口的方法聲明,内部知識簡單地調用了父類即 proxy 的 h 屬性的 ​<code>​invoke​</code>​ 方法

JDK 與 Cglib 的使用和對比

再回看 proxy 類的屬性

JDK 與 Cglib 的使用和對比

可以猜測,對被代理方法進行調用時,會轉而由被代理類中繼承自 proxy 的 invocationhandler 執行,進而 ​<code>​invoke​</code>​方法被調用。再來看看調用的 ​<code>​newproxyinstance​</code>​ 的邏輯,代碼進行了省略,添加了簡單注釋

目前還有一個問題沒搞明白:調用 ​<code>​invoke​</code>​ 時,參數中的 method 能夠争取比對到調用的方法,該比對是如何實作的?

JDK 與 Cglib 的使用和對比
JDK 與 Cglib 的使用和對比

概括一下,cglib 動态代理的方式一般為:

構造 enhancer

設定代理對象(作為父類)

設定代理政策

建立代理對象

callback 可以了解成生成的代理類的方法被調用時會執行的邏輯,具有以下六種方式:

noop:不做任何操作

fixedvalue:要求實作接口的 <code>loadobjecd</code> 方法,重寫了被代理類的響應方法,同時,要求傳回值和方法傳回值相同,否則會抛出類型轉換異常。此方式看不到人喝原方法的資訊,也無法調用原方法。

methodinterceptor:類似 aop 的環繞增強,代理類的方法調用都會轉入執行該接口的 <code>intercept</code> 方法。需要執行原方法可以使用參數 method 進行反射調用,或者使用參數 proxy(proxy會快一些)

invocationhandler:類似 methodinterceptor,若自定義該接口的 <code>invoke</code> 方法,需要注意參數 method 的 <code>invoke</code>方法,會無限循環調用

lazyloader:調用時,傳回一個代理對象并存儲負責所有的該代理類調用,類似 spring 的 singleton

dispatcher:每次調用都會傳回一個新的代理類,類似 spring 的 prototye

<col>

jdk

cglib

代理目标

接口

類(被代理類會作為父類,無法處理 final)

實作

反射機制

運作過程中修改被代理類的 class 檔案位元組碼

spring采用政策

目标對象實作接口時采用

目标對象未實作接口時采用

預設為 jdk ,使用時可以進行指定