1. 程式人生 > >【Java入門提高篇】Day12 Java代理——Cglib動態代理

【Java入門提高篇】Day12 Java代理——Cglib動態代理

效率 object urn 而且 什麽 tor clas ams 提高

  今天來介紹另一種更為強大的代理——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動態代理