posts - 0,  comments - 6,  trackbacks - 0

          代理模式的定義

              代理模式用于為某一個(gè)對(duì)象提供一個(gè)替身(一個(gè)代理對(duì)象),并通過(guò)這個(gè)替身控制客戶(hù)代碼對(duì)這個(gè)對(duì)象的訪問(wèn)。代理模式屬于對(duì)象的結(jié)構(gòu)模式。

              下面是一些使用代理模式的場(chǎng)合:

          用遠(yuǎn)程代理控制訪問(wèn)遠(yuǎn)程對(duì)象

          虛擬代理控制訪問(wèn)創(chuàng)建開(kāi)銷(xiāo)大的資源對(duì)象

          保護(hù)代理基于權(quán)限控制對(duì)資源的訪問(wèn)


              首先,讓我們來(lái)看一下代理模式的結(jié)構(gòu)類(lèi)圖:


          代理模式簡(jiǎn)單例子

          業(yè)務(wù)接口

          public interface IHello {

          /** 假設(shè)這是一個(gè)業(yè)務(wù)方法*/

          void sayHello(String name);

          }

          業(yè)務(wù)實(shí)現(xiàn)類(lèi)

          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("鄭州蜂鳥(niǎo)科技");

          }

          }

          運(yùn)行輸出:Hello 鄭州蜂鳥(niǎo)科技

              接下來(lái),我們希望對(duì)所有該業(yè)務(wù)方法進(jìn)行性能測(cè)試,即計(jì)算業(yè)務(wù)方法執(zhí)行消耗的時(shí)間。要求不能修改原來(lái)的代碼,但是可以擴(kuò)展新的類(lèi)。也就是要滿(mǎn)足面向?qū)ο笤O(shè)計(jì)原則:開(kāi)閉原則(對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉)。

          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("鄭州蜂鳥(niǎo)科技");

          }

          }

          輸出結(jié)果:

          sayHello method start time:1290077898984

          Hello 鄭州蜂鳥(niǎo)科技

          sayHello method end time:1290077898984

          Total time:0

              以上代理模式只是概念上的設(shè)計(jì)和實(shí)現(xiàn),實(shí)用性比較差。它有很多問(wèn)題,比如,我們有很多不同業(yè)務(wù)類(lèi)的不同業(yè)務(wù)方法都需要進(jìn)行性能測(cè)試,那么我們就需要些很多代理類(lèi),并為每個(gè)代理類(lèi)設(shè)計(jì)很多方法。這簡(jiǎn)直是類(lèi)和方法的爆炸。解決這一問(wèn)題的方案是動(dòng)態(tài)代理技術(shù)。

          動(dòng)態(tài)代理模式

          針對(duì)接口的動(dòng)態(tài)代理:JDK對(duì)動(dòng)態(tài)代理模式的支持

              Java 在 java.lang.reflect 包中有自己對(duì)代理模式的支持,你可以在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建一個(gè)代理類(lèi),實(shí)現(xiàn)一個(gè)或多個(gè)接口,并將方法的調(diào)用轉(zhuǎn)發(fā)到你所指定的類(lèi),我們稱(chēng)之為動(dòng)態(tài)代理。請(qǐng)看結(jié)構(gòu)類(lèi)圖:


          Hello創(chuàng)建動(dòng)態(tài)代理,而且它可以為任何實(shí)現(xiàn)了接口的類(lèi)型創(chuàng)建代理:

          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(),//加載目標(biāo)對(duì)象類(lèi)型的類(lèi)加載器

          cls.getInterfaces(), //目標(biāo)對(duì)象類(lèi)型實(shí)現(xiàn)的接口

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

          }

          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;

          }

          }

          測(cè)試代碼:

          public static void main(String[] args) {

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

          hello.sayHello("蜂鳥(niǎo)科技");

          }

          執(zhí)行結(jié)果:

          class $Proxy0

          sayHello method start time:1284427181218

          蜂鳥(niǎo)科技

          Hello 蜂鳥(niǎo)科技

          sayHello method end time:1284427181265

          Total time:47

              使用JDK創(chuàng)建代理有一個(gè)限制,即它只能為接口創(chuàng)建代理,這一點(diǎn)我們從Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)就看得很清楚,第三個(gè)入?yún)?/font>interfaces就是為代理實(shí)例指定的實(shí)現(xiàn)接口。雖然,面向接口的編程被很多很有影響力人(包括Rod Johnson)的推崇,但在實(shí)際開(kāi)發(fā)中,開(kāi)發(fā)者也遇到了很多困惑:難道對(duì)一個(gè)簡(jiǎn)單業(yè)務(wù)表的操作真的需要?jiǎng)?chuàng)建5個(gè)類(lèi)(領(lǐng)域?qū)ο箢?lèi)、Dao接口,Dao實(shí)現(xiàn)類(lèi),Service接口和Service實(shí)現(xiàn)類(lèi))嗎?對(duì)于這一問(wèn)題,我們還是留待大家進(jìn)一步討論。現(xiàn)在的問(wèn)題是:對(duì)于沒(méi)有通過(guò)接口定義業(yè)務(wù)方法的類(lèi),如何動(dòng)態(tài)創(chuàng)建代理實(shí)例呢?JDK的代理技術(shù)顯然已經(jīng)黔驢技窮,CGLib作為一個(gè)替代者,填補(bǔ)了這個(gè)空缺。你可以從http://cglib.sourceforge.net/獲取CGLib的類(lèi)包,也可以直接從Spring的關(guān)聯(lián)類(lèi)庫(kù)lib/cglib中獲取類(lèi)包。

          針對(duì)類(lèi)的動(dòng)態(tài)代理:CGLIB動(dòng)態(tài)代理庫(kù)

              CGLib采用非常底層的字節(jié)碼技術(shù),可以為一個(gè)類(lèi)創(chuàng)建子類(lèi),并在子類(lèi)中采用方法攔截的技術(shù)攔截所有父類(lèi)方法的調(diào)用,并在攔截方法相應(yīng)地織入橫切邏輯。下面,我們采用CGLib技術(shù),編寫(xiě)一個(gè)可以為任何類(lèi)創(chuàng)建織入性能監(jiān)視橫切邏輯的代理對(duì)象的代理器,如代碼所示:

          public class DynamicCglibProxy implements MethodInterceptor {

          private Enhancer enhancer = new Enhancer();

          public Object getProxy(Class clazz) {

          enhancer.setSuperclass(clazz);// ① 設(shè)置需要?jiǎng)?chuàng)建子類(lèi)的類(lèi)

          enhancer.setCallback(this);

          return enhancer.create(); // ②通過(guò)字節(jié)碼技術(shù)動(dòng)態(tài)創(chuàng)建子類(lèi)實(shí)例

          }

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

          MethodProxy proxy) throws Throwable {

              System.out.println(obj.class);//看看動(dòng)態(tài)生成的對(duì)象的類(lèi)型;

          long start = System.currentTimeMillis();

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

                  

          Object result = proxy.invokeSuper(obj, args); // ③ 通過(guò)代理類(lèi)調(diào)用父類(lèi)中的方法

          long end = System.currentTimeMillis();

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

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

          return result;

          }

          }

          在上面代碼中,你可以通過(guò)getProxy(Class clazz)為一個(gè)類(lèi)創(chuàng)建動(dòng)態(tài)代理對(duì)象,該代理對(duì)象是指定類(lèi)clazz的子類(lèi)。在這個(gè)代理對(duì)象中,我們織入性能監(jiān)視的橫切邏輯(粗體部分)。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)CGLib定義的Inerceptor接口的方法,obj表示父類(lèi)的實(shí)例,method為父類(lèi)方法的反射對(duì)象,args為方法的動(dòng)態(tài)入?yún)ⅲ?/font>proxy為代理類(lèi)實(shí)例。

          下面,我們通過(guò)CglibProxyForumServiceImpl類(lèi)創(chuàng)建代理對(duì)象,并測(cè)試代理對(duì)象的方法,如代碼所示:

          public static void main(String[] args) {

          DynamicCglibProxy proxy = new DynamicCglibProxy();

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

          h.sayHello("蜂鳥(niǎo)科技");

          }

          執(zhí)行結(jié)果:

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

          sayHello method start time:1284427305921

          Hello 蜂鳥(niǎo)科技

          sayHello method end time:1284427305968

          Total time:47

          到這里我們簡(jiǎn)單掌握了代理模式。動(dòng)態(tài)代理在struts2、hibernate和spring中都大量使用到了,這將對(duì)我們理解這些框架有很大意義。有時(shí)間我們來(lái)模擬實(shí)現(xiàn)這些框架的部分功能。

          學(xué)軟件開(kāi)發(fā),到蜂鳥(niǎo)科技!
          超強(qiáng)的師資力量 、完善的課程體系 、超低的培訓(xùn)價(jià)格 、真實(shí)的企業(yè)項(xiàng)目。

          網(wǎng)址:www.ntcsoft.com 
          電話(huà):0371-63839606 
          鄭州軟件開(kāi)發(fā)興趣小組群:38236716

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

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          留言簿(2)

          我參與的團(tuán)隊(duì)

          文章檔案(22)

          搜索

          •  

          最新評(píng)論

          主站蜘蛛池模板: 进贤县| 大冶市| 大关县| 石家庄市| 天津市| 满城县| 济南市| 宁河县| 亳州市| 酒泉市| 宁夏| 扬州市| 荣成市| 武山县| 会宁县| 环江| 西青区| 轮台县| 汤原县| 衡东县| 金山区| 宁波市| 彰武县| 玛曲县| 莱州市| 西乌珠穆沁旗| 诸城市| 寿阳县| 成都市| 平定县| 县级市| 江陵县| 前郭尔| 合江县| 平乡县| 遂宁市| 轮台县| 唐海县| 乳山市| 清远市| 澄江县|