posts - 0,  comments - 6,  trackbacks - 0

          代理模式的定義

              代理模式用于為某一個對象提供一個替身(一個代理對象),并通過這個替身控制客戶代碼對這個對象的訪問。代理模式屬于對象的結構模式。

              下面是一些使用代理模式的場合:

          用遠程代理控制訪問遠程對象

          虛擬代理控制訪問創建開銷大的資源對象

          保護代理基于權限控制對資源的訪問


              首先,讓我們來看一下代理模式的結構類圖:


          代理模式簡單例子

          業務接口

          public interface IHello {

          /** 假設這是一個業務方法*/

          void sayHello(String name);

          }

          業務實現類

          public class Hello implements IHello {

              public void sayHello(String name) {

                  System.out.println("Hello " + name);

              }

              public static void main(String[] args) {

               IHello hello = new Hello();

          hello.sayHello("鄭州蜂鳥科技");

          }

          }

          運行輸出:Hello 鄭州蜂鳥科技

              接下來,我們希望對所有該業務方法進行性能測試,即計算業務方法執行消耗的時間。要求不能修改原來的代碼,但是可以擴展新的類。也就是要滿足面向對象設計原則:開閉原則(對擴展開放,對修改關閉)。

          public class StaticHelloProxy implements IHello {

              private IHello hello;

           

              public StaticHelloProxy(IHello hello) {

                   this.hello = hello;

              }

           

              public void sayHello(String name) {

               long start = System.currentTimeMillis();

                  System.out.println("sayHello method start time:"+start);

                  hello.sayHello(name);

                  long end = System.currentTimeMillis();

                  System.out.println("sayHello method end time:"+end);

                  System.out.println("Total time:"+(end - start));

              }

              

              public static void main(String[] args) {

          IHello hello = new StaticHelloProxy(new Hello());

          hello.sayHello("鄭州蜂鳥科技");

          }

          }

          輸出結果:

          sayHello method start time:1290077898984

          Hello 鄭州蜂鳥科技

          sayHello method end time:1290077898984

          Total time:0

              以上代理模式只是概念上的設計和實現,實用性比較差。它有很多問題,比如,我們有很多不同業務類的不同業務方法都需要進行性能測試,那么我們就需要些很多代理類,并為每個代理類設計很多方法。這簡直是類和方法的爆炸。解決這一問題的方案是動態代理技術。

          動態代理模式

          針對接口的動態代理:JDK對動態代理模式的支持

              Java 在 java.lang.reflect 包中有自己對代理模式的支持,你可以在運行時動態創建一個代理類,實現一個或多個接口,并將方法的調用轉發到你所指定的類,我們稱之為動態代理。請看結構類圖:


          Hello創建動態代理,而且它可以為任何實現了接口的類型創建代理:

          public class DynamicJdkProxy implements InvocationHandler {

          private Object proxyobj;

          public DynamicJdkProxy(Object obj) {

          proxyobj = obj;

          }

          public static Object factory(Object obj) {

          Class cls = obj.getClass();

          return Proxy.newProxyInstance(

          cls.getClassLoader(),//加載目標對象類型的類加載器

          cls.getInterfaces(), //目標對象類型實現的接口

          new DynamicJdkProxy(obj));//代理對象

          }

          public Object invoke(Object proxy, Method method, Object[] args)

          throws Throwable {

                  System.out.println(proxy.getClass());

          long start = System.currentTimeMillis();

                  System.out.println("sayHello method start time:"+start);

          if (args != null) {

          for (int i = 0; i < args.length; i++) {

          System.out.println(args[i] + "");

          }

          }

          Object o = method.invoke(proxyobj, args);

          long end = System.currentTimeMillis();

                  System.out.println("sayHello method end time:"+end);

                  System.out.println("Total time:"+(end - start));

          return o;

          }

          }

          測試代碼:

          public static void main(String[] args) {

          IHello hello = (IHello) DynamicJdkProxy.factory(new Hello());

          hello.sayHello("蜂鳥科技");

          }

          執行結果:

          class $Proxy0

          sayHello method start time:1284427181218

          蜂鳥科技

          Hello 蜂鳥科技

          sayHello method end time:1284427181265

          Total time:47

              使用JDK創建代理有一個限制,即它只能為接口創建代理,這一點我們從Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)就看得很清楚,第三個入參interfaces就是為代理實例指定的實現接口。雖然,面向接口的編程被很多很有影響力人(包括Rod Johnson)的推崇,但在實際開發中,開發者也遇到了很多困惑:難道對一個簡單業務表的操作真的需要創建5個類(領域對象類、Dao接口,Dao實現類,Service接口和Service實現類)嗎?對于這一問題,我們還是留待大家進一步討論?,F在的問題是:對于沒有通過接口定義業務方法的類,如何動態創建代理實例呢?JDK的代理技術顯然已經黔驢技窮,CGLib作為一個替代者,填補了這個空缺。你可以從http://cglib.sourceforge.net/獲取CGLib的類包,也可以直接從Spring的關聯類庫lib/cglib中獲取類包。

          針對類的動態代理:CGLIB動態代理庫

              CGLib采用非常底層的字節碼技術,可以為一個類創建子類,并在子類中采用方法攔截的技術攔截所有父類方法的調用,并在攔截方法相應地織入橫切邏輯。下面,我們采用CGLib技術,編寫一個可以為任何類創建織入性能監視橫切邏輯的代理對象的代理器,如代碼所示:

          public class DynamicCglibProxy implements MethodInterceptor {

          private Enhancer enhancer = new Enhancer();

          public Object getProxy(Class clazz) {

          enhancer.setSuperclass(clazz);// ① 設置需要創建子類的類

          enhancer.setCallback(this);

          return enhancer.create(); // ②通過字節碼技術動態創建子類實例

          }

          public Object intercept(Object obj, Method method, Object[] args,

          MethodProxy proxy) throws Throwable {

              System.out.println(obj.class);//看看動態生成的對象的類型;

          long start = System.currentTimeMillis();

                  System.out.println("sayHello method start time:"+start);

                  

          Object result = proxy.invokeSuper(obj, args); // ③ 通過代理類調用父類中的方法

          long end = System.currentTimeMillis();

          System.out.println("sayHello method end time:"+end);

                  System.out.println("Total time:"+(end - start));

          return result;

          }

          }

          在上面代碼中,你可以通過getProxy(Class clazz)為一個類創建動態代理對象,該代理對象是指定類clazz的子類。在這個代理對象中,我們織入性能監視的橫切邏輯(粗體部分)。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)CGLib定義的Inerceptor接口的方法,obj表示父類的實例,method為父類方法的反射對象,args為方法的動態入參,而proxy為代理類實例。

          下面,我們通過CglibProxyForumServiceImpl類創建代理對象,并測試代理對象的方法,如代碼所示:

          public static void main(String[] args) {

          DynamicCglibProxy proxy = new DynamicCglibProxy();

          Hello h = (Hello) proxy.getProxy(Hello.class);

          h.sayHello("蜂鳥科技");

          }

          執行結果:

          class com.ntcsoft.proxy.noproxy.Hello$$EnhancerByCGLIB$$127f0ad5

          sayHello method start time:1284427305921

          Hello 蜂鳥科技

          sayHello method end time:1284427305968

          Total time:47

          到這里我們簡單掌握了代理模式。動態代理在struts2、hibernate和spring中都大量使用到了,這將對我們理解這些框架有很大意義。有時間我們來模擬實現這些框架的部分功能。

          學軟件開發,到蜂鳥科技!
          超強的師資力量 、完善的課程體系 、超低的培訓價格 、真實的企業項目。

          網址:www.ntcsoft.com 
          電話:0371-63839606 
          鄭州軟件開發興趣小組群:38236716

          posted on 2010-11-26 01:01 whistler 閱讀(430) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          留言簿(2)

          我參與的團隊

          文章檔案(22)

          搜索

          •  

          最新評論

          主站蜘蛛池模板: 河曲县| 吉木乃县| 睢宁县| 灵武市| 镇巴县| 信丰县| 霍城县| 台南市| 麻栗坡县| 台东市| 昌平区| 梁平县| 临泉县| 新宾| 资源县| 漠河县| 太谷县| 吴旗县| 五华县| 斗六市| 绥棱县| 武宣县| 朝阳县| 深圳市| 四川省| 错那县| 积石山| 南投市| 平顺县| 通河县| 麻城市| 慈利县| 鹿邑县| 获嘉县| 德化县| 大田县| 安图县| 视频| 柳州市| 公安县| 和顺县|