標籤:情況 ade stc java代理 [] cep test param out
今天來介紹另一種更為強大的代理——Cglib動態代理。
什麼是Cglib動態代理?
我們先回顧一下上一篇的jdk動態代理,jdk動態代理是通過介面來在運行時動態建立委託類的代理對象,但是跟靜態代理一樣有一個缺點,就是必須和委託類實現相同的介面,當介面數量增加時,便需要增加代理類的數量才能滿足需求,而且如果委託類是別人寫的,而且沒有實現任何介面,那麼jdk動態代理就有些力不從心了。
這時候Cglib動態代理就脫穎而出了,Cglib並不依賴介面,可以直接產生委託類的代理對象,而且可以代理委託類的任意非final修飾的public和protected方法,我們可以先來看一個栗子。
先定義一個Programmer類:
public class Programmer { private String name; public void setName(String name) {
System.out.println("Setting Name."); this.name = name; }public void code(){ System.out.println(name + " is writing bugs."); }}
然後定義一個代理類:
public class ProgrammerProxy implements MethodInterceptor { /** * 內部持有委託類對象的引用 */ private Object target; /** * 建立代理類對象 */ public Programmer createProxy(Programmer object){ target = object; //建立Enhancer對象 Enhancer enhancer = new Enhancer(); //設定要代理的目標類,以擴充功能 enhancer.setSuperclass(this.target.getClass()); //設定單一回調對象,在回調中攔截對目標方法的調用 enhancer.setCallback(this); //設定類載入器 enhancer.setClassLoader(object.getClass().getClassLoader()); //建立代理對象 return (Programmer)enhancer.create(); } /** * 回調方法:在代理執行個體上攔截並處理目標方法的調用,返回結果 * @param proxy 代理類 * @param method 被代理的方法 * @param params 該方法的參數數組 * @param methodProxy */ @Override public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { //調用之前處理 doBefore(); //調用原方法 method.invoke(target,params); //調用之後處理 doAfter(); return null; } private void doAfter() { System.out.println("do after."); } private void doBefore() { System.out.println("do before."); }}
然後測試一下:
public class ProxyTest { @Test public void testCglibProxy(){ //建立一個Programmer對象 Programmer programmerA = new Programmer(); programmerA.setName("Frank"); //建立代理對象 Programmer programmerProxyA = new ProgrammerProxy().createProxy(programmerA); programmerProxyA.code(); //修改代理對象 programmerProxyA.setName("Wang"); programmerProxyA.code(); //修改委託類對象 programmerA.setName("Song"); programmerProxyA.code(); }}
輸出如下:
Setting Name.do before.Frank is writing bugs.do after.do before.Setting Name.do after.do before.Wang is writing bugs.do after.Setting Name.do before.Song is writing bugs.do after.
Cglib實現動態代理的步驟也不是很麻煩,先建立一個類實現MethodInterceptor介面,重寫intercept方法,在intercep中可以截獲委託類的所有非final修飾的public和protected方法,上例中,method.invoke(target,params);即為調用原對象的原方法,在代理類中儲存了委託類對象的引用,這一點跟JDK動態代理是一樣的。在調用原方法前先調用了doBefore方法,調用之後還調用了doAfter方法,從而實現了代理功能。至於createProxy方法,也只是一個固定步驟,先建立Enhance對象,然後將委託類的一些屬性往裡塞,然後調用create方法來動態組建代理程式對象。
在測試類別中,為了更明顯的說明代理類與委託類的關係,分別用代理類對象programmerProxyA和委託類對象programmerA對name欄位進行修改,可以產生一樣的效果。
下面來對比一下Cglib動態代理與JDK動態代理:
1.兩者都是動態代理,都是運行時動態組建代理程式對象。
2.JDK動態代理利用的是介面資訊來實現的代理,委託類必須實現某個或者某些介面,而Cglib則是利用繼承關係,利用asm在運行時動態產生委託類的子類,從而實現對委託類的代理。因此不依賴介面。
3.Cglib由於是利用繼承關係來實現代理的,因此無法代理被final修飾的類以及被final修飾的方法。
4.Cglib一般來說效率要比JDK動態代理效率更高,可以實現的代理也更為強大。
當然,具體情況具體分析,雖然Cglib比Jdk動態代理更強大,但並不一定各個地方都強行使用,有時候JDK動態代理相對來說更加簡單粗暴。
至此,本篇完結,代理相關內容講解完畢,歡迎大家繼續關注。
【Java入門提高篇】Day12 Java代理——Cglib動態代理