動態(tài)代理

上篇文章講了什么是代理模式,為什么用代理模式,從靜態(tài)代理過渡到動態(tài)代理。

這里再簡單總結一下

  • 什么是代理模式,給某個對象提供一個代理對象,并由代理對象控制對于原對象的訪問,即客戶不直接操控原對象,而是通過代理對象間接地操控原對象。

  • 靜態(tài)代理是在程序發(fā)布之前,我們就必須寫好代理類的

  • 動態(tài)代理在程序發(fā)布之前,并沒有寫好代理類,而是發(fā)布之后,動態(tài)創(chuàng)建代理對象的

這篇文章主要介紹兩種動態(tài)代理,jdk代理和cglib代理

jdk代理

實現(xiàn)

  • 通過實現(xiàn) InvocationHandler 接口創(chuàng)建自己的調(diào)用處理器

  • 通過為 Proxy 類指定 ClassLoader 對象和一組 interface 來創(chuàng)建動態(tài)代理類

  • 通過反射機制獲得動態(tài)代理類的構造函數(shù)

  • 通過構造函數(shù)創(chuàng)建動態(tài)代理類實例,構造時調(diào)用處理器對象作為參數(shù)被傳入

代碼

 Sale saleProxy=(Sale)Proxy.newProxyInstance( jiajun.getClass().getClassLoader(), jiajun.getClass().getInterfaces(), 
               new InvocationHandler() { 
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
                    { 
                        System.out.println("===before==="); 
                        Object obj = method.invoke(jiajun, args);
                        System.out.println("===after==="); return obj; } 
                    });
                         
       saleProxy.sale();
       saleProxy.rent();

原理

  • 生成一個代理類,這個代理類繼承Proxy類并且實現(xiàn)了我們定義的接口,代理對象調(diào)用方法的時候,調(diào)用這個代理對象的一個成員InvocationHandler(上面我們傳入了一個InvocationHandler實現(xiàn)對象)的方法,也就是我們添加了before和after后的方法。

cglib代理

實現(xiàn)

  • 實現(xiàn)CGLib包提供的MethodInterceptor接口,實現(xiàn)intercept方法,用CGLib中的Enhancer的creat方法創(chuàng)建代理對象

代碼

class CGLibProxy implements MethodInterceptor {    public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
        System.out.println("Before:" + method);  
        Object object = proxy.invokeSuper(obj, arg);
        System.out.println("After:" + method); 
        return object;
    }
}public class Test2 {    public static void main(String[] args) {
        CGLibProxy cgLibProxy=new CGLibProxy();
        Jiajun jiajunProxy=(Jiajun)Enhancer.create(Jiajun.class,cgLibProxy);
        jiajunProxy.buy();
        jiajunProxy.sale();
    }
}

原理

  • 通過asm字節(jié)碼生成框架生成代理類Class的二進制字節(jié)碼

  • 通過Class.forName加載二進制字節(jié)碼,生成Class對象

  • 通過反射機制獲取實例構造,并初始化代理類對象

jdk代理 vs cglib代理

  • jdk代理只能代理接口,不能代理沒有接口的類。

  • cglib代理可以代理沒有接口的類

總結

  • 動態(tài)代理相對于靜態(tài)代理更加靈活,減少了代碼量也提高了可維護性。

  • 動態(tài)代理有兩種,一種是jdk代理,通過創(chuàng)建一個繼承Proxy類并實現(xiàn)接口的代理對象。一種是cglib代理,通過asm生成代理類class的字節(jié)碼,再生成Class對象,最后通過反射創(chuàng)建代理對象。

  • jdk代理只適合基于接口的代理,cglib可以代理沒有實現(xiàn)接口的目標對象。

我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鐘、半秒鐘,哪怕說一句話有點道理,引發(fā)自己內(nèi)心的感觸,這就是我最大的價值。(這是我喜歡的一句話,也是我寫博客的初衷)

http://www.cnblogs.com/-new/p/7151136.html