spring aop 依靠 jdk 和 cglib 進行動态代理實作。在此對兩種實作方式的一些知識進行整理。
可見代理成功。
概括一下,動态代理的方式一般為:
繼承 <code>invocationhandler</code> ,重寫方法 <code>invoke</code>
執行 <code>proxy.newproxyinstance</code> 生成動态代理類
由上可以看出,proxy 成功對 iinterface 接口進行代理,但是在使用時,我們并未見到 invocationhandler 中 <code>invoke</code> 方法的調用,動态代理是如何執行 <code>invoke</code> 的呢?
采用其他資料生成的案例,以下是代理類的反編譯代碼。
首先來看看代理類的繼承關系:
可以看到代理類繼承了 proxy ,再來看看代理類中的方法調用,其中 <code>teach()</code> 是被代理接口的方法聲明,内部知識簡單地調用了父類即 proxy 的 h 屬性的 <code>invoke</code> 方法
再回看 proxy 類的屬性
可以猜測,對被代理方法進行調用時,會轉而由被代理類中繼承自 proxy 的 invocationhandler 執行,進而 <code>invoke</code>方法被調用。再來看看調用的 <code>newproxyinstance</code> 的邏輯,代碼進行了省略,添加了簡單注釋
目前還有一個問題沒搞明白:調用 <code>invoke</code> 時,參數中的 method 能夠争取比對到調用的方法,該比對是如何實作的?
概括一下,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 ,使用時可以進行指定