動態代理學習筆記 jdk vs cglib
spring有兩個重要的思想,一個是IOC一個是AOP。AOP的原理就是基於java的動態代理機制。java實現動態代理的方式,由兩種組成,一種是基於jdk自帶的基於介面的動態代理方式,另一種則是使用cglib基於類的動態代理方式。
先上結論,給出兩種動態代理的比較。
1、基於jdk的動態代理
1-1、關鍵類或介面
1-2、調用過程
a、new一個自定義類的對象
b、實現InvocationHandler介面
c、使用Proxy生成代理對象,調用Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h) 參數分別為實現handler的類的classloader、自定義介面、實現InvocationHandler的對象。並強制轉換成自定義介面類
d、通過自定義介面調用方法,實現對自定義類的動態調用。
動態代理最終調用的是生成的代理對象,而1-2所列舉的過程,只是說了怎麼用,程序員嘛,不但要知道怎麼用,最好還是要知道一下原理,以後才能發明創造,走向人生巔峰。
1-3、生成代理對象的原理解析
a、生成代理類從這句話開始
b、跟著代碼一路跳轉先讀取緩存,如果緩存沒有再新建類,最後到達ProxyClassFactory的public Class apply(ClassLoader loader, Class[] interfaces),下圖是生成代理類的關鍵代碼,生成代理類位元組流,並使用defineclass0生成位元組碼文件,就是.class文件
defineClass0是一個native方法,他會生成位元組碼文件,下圖就是它生成的文件,最後我們會利用反編譯工具看一下,裡面到底寫了點什麼代碼。
c、生成了class類,那麼接下來要進行初始化對象了
首先Proxy獲取了構造方法,並將我們實現的InvocationHandler對象傳入,通過構造方法實例化了代理類對象。
1-4、了解代理類的內部結構,幫助理解
a、生成的Proxy0繼承了Proxy又實現了我自己的自定義介面Network
b、這個browse()方法就是我自定義介面Network中的抽象方法,可以看到他是通過調用傳入的InvocationHandler中的invoke方法來最終實現動態調用的。
2、cglib動態調用
2-1、關鍵類或介面
自己實現的代理工廠需要實現MethodInterceptor介面及使用Enhancer.create()來創建對象。
2-2、調用過程
a、實例一個自定義代理類,代理類代碼如下。實現MethodInterceptor介面,並設置父類,以及回調函數。
b、將需要代理的對象類傳入並調用
2-3、生成代理對象的原理解析
a、生成代理類基本和jdk版本的差不多也都是先讀取緩存,然後到達Enhancer類中的下面方法
b、然後經過AbstractClassGenerator.class、DefaultGeneratorStrategy.class回到Enhancer的generateClass(ClassVisitor v)方法設置ClassVisitor的熟悉,最後再回到DefaultGeneratorStrategy.class將ClassVisitor轉換成位元組流(這裡轉換成位元組流用的是asm框架),並通過asm框架中的define方法生成位元組碼文件,也就是.class文件。
c、通過AbstractClassGenerator中create(Object key)方法中nextInstance(obj)實例化對象,實例化過程與jdk類似,都是通過構造函數進行。
2-4、了解代理類的內部結構,幫助理解
有三個,主要看第二個。
可以發現繼承了要代理的類。
由於反編譯有點問題,我就不貼其中代碼了,不過可以想到,既然繼承了我們要代理的對象,那麼就能重寫其中的非final方法,然後通過我們前面寫的回調方法對代理對象進行調用,這個很像InvocationHandler在jdk動態代理中的作用。
特別的要說一下,攔截器中我們使用invokeSuper進行對象方法的調用,其中
Cglib採用了FastClass機制,它的原理簡單來說就是:為代理類和被代理類各生成一個Class,這個Class會為代理類或被代理類的方法分配一個index(int類型)。這個index當做一個入參,FastClass就可以直接定位要調用的方法直接進行調用,這樣省去了反射調用,所以調用效率比JDK動態代理通過反射調用高。這也就是其他生成的兩個.class的作用。


※戀愛中,「分手」說一次就好,婚姻里,「離婚」請不要輕易說出口
※香港有哪些值得購買的東西?
TAG:全球大搜羅 |