andy-j2ee  
          JAVA
          公告
          • 在夜深人靜的時候,偶彈起心愛的土琵琶,唱起那動人的歌謠(柯受良-《大哥》):偶寫了代碼好多年,偶不愛冰冷的床沿,不要逼偶想念,不要逼偶流淚,偶會翻。
          日歷
          <2011年10月>
          2526272829301
          2345678
          9101112131415
          16171819202122
          23242526272829
          303112345
          統(tǒng)計
          • 隨筆 - 19
          • 文章 - 1
          • 評論 - 1
          • 引用 - 0

          導航

          常用鏈接

          留言簿

          隨筆分類(5)

          隨筆檔案(19)

          文章分類(1)

          文章檔案(1)

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

           
          原文http://blog.zdnet.com.cn/html/90/289390-838716.htmlJDK動態(tài)代理
             
           1 package com.baobaotao.proxy; 在JDK 1.3以后提供了動態(tài)代理的技術,允許開發(fā)者在運行期創(chuàng)建接口的代理實例。在Sun剛推出動態(tài)代理時,還很難想象它有多大的實際用途,現(xiàn)在我們終于發(fā)現(xiàn)動態(tài)代理是實現(xiàn)AOP的絕好底層技術。
              JDK的動態(tài)代理主要涉及到java.lang.reflect包中的兩個類:Proxy和InvocationHandler。其中InvocationHandler是一個接口,可以通過實現(xiàn)該接口定義橫切邏輯,在并通過反射機制調(diào)用目標類的代碼,動態(tài)將橫切邏輯和業(yè)務邏輯編織在一起。
             而Proxy為InvocationHandler實現(xiàn)類動態(tài)創(chuàng)建一個符合某一接口的代理實例。這樣講一定很抽象,我們馬上著手動用Proxy和InvocationHandler這兩個魔法戒對上一節(jié)中的性能監(jiān)視代碼進行AOP式的改造。
              首先,我們從業(yè)務類ForumServiceImpl 中刪除性能監(jiān)視的橫切代碼,使ForumServiceImpl只負責具體的業(yè)務邏輯,如所示:
          代碼清單 5 ForumServiceImpl:移除性能監(jiān)視橫切代碼
              
           2 
           3 public class ForumServiceImpl implements ForumService {
           4 
           5  public void removeTopic(int topicId) {
           6          ①
           7   System.out.println("模擬刪除Topic記錄:"+topicId);
           8   try {
           9    Thread.currentThread().sleep(20);
          10   } catch (Exception e) {
          11    throw new RuntimeException(e);
          12   }
          13    ②
          14  }
          15  public void removeForum(int forumId) {
          16          ①
          17   System.out.println("模擬刪除Forum記錄:"+forumId);
          18   try {
          19    Thread.currentThread().sleep(40);
          20   } catch (Exception e) {
          21    throw new RuntimeException(e);
          22   }
          23          ②
          24  }
          25 }
              
          在代碼清單 5中的①和②處,原來的性能監(jiān)視代碼被移除了,我們只保留了真正的業(yè)務邏輯。
              從業(yè)務類中移除的橫切代碼當然還得找到一個寄居之所,InvocationHandler就是橫切代碼的家園樂土,我們將性能監(jiān)視的代碼安置在PerformaceHandler中,如代碼清單 6所示:
          代碼清單 6 PerformaceHandler
           1 package com.baobaotao.proxy;
              
           2 import java.lang.reflect.InvocationHandler;
           3 import java.lang.reflect.Method;
           4 
           5 public class PerformaceHandler implements InvocationHandler {
           6     private Object target;
           7  public PerformaceHandler(Object target){//①target為目標的業(yè)務類
           8   this.target = target;
           9  }
          10  public Object invoke(Object proxy, Method method, Object[] args)
          11    throws Throwable {
          12   PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
          13   Object bj = method.invoke(target, args);//②通過反射方法調(diào)用目標業(yè)務類的業(yè)務方法
          14   PerformanceMonitor.end();
          15   return obj;
          16  }
          17 }
              
           粗體部分的代碼為性能監(jiān)視的橫切代碼,我們發(fā)現(xiàn),橫切代碼只出現(xiàn)一次,而不是原來那樣星灑各處。大家注意②處的method.invoke(),該語句通過反射的機制調(diào)用目標對象的方法,這樣InvocationHandler的invoke(Object proxy, Method method, Object[] args)方法就將橫切代碼和目標業(yè)務類代碼編織到一起了,所以我們可以將InvocationHandler看成是業(yè)務邏輯和橫切邏輯的編織器。下面,我們對這段代碼做進一步的說明。
          首先,我們實現(xiàn)InvocationHandler接口,該接口定義了一個 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理實例,一般不會用到;method是代理實例上的方法,通過它可以發(fā)起對目標類的反射調(diào)用;args是通過代理類傳入的方法參數(shù),在反射調(diào)用時使用。
              此外,我們在構(gòu)造函數(shù)里通過target傳入真實的目標對象,如①處所示,在接口方法invoke(Object proxy, Method method, Object[] args)里,將目標類實例傳給method.invoke()方法,通過反射調(diào)用目標類方法,如②所示。
              下面,我們通過Proxy結(jié)合PerformaceHandler創(chuàng)建ForumService接口的代理實例,如代碼清單 7所示:
          代碼清單 7 TestForumService:創(chuàng)建代理實例
           1 package com.baobaotao.proxy;
              
           2 import java.lang.reflect.Proxy;
           3 public class TestForumService {
           4  public static void main(String[] args) {
           5   ForumService target = new ForumServiceImpl();//①目標業(yè)務類
           6 //② 將目標業(yè)務類和橫切代碼編織到一起
           7   PerformaceHandler handler = new PerformaceHandler(target);
           8          //③為編織了目標業(yè)務類邏輯和性能監(jiān)視橫切邏輯的handler創(chuàng)建代理類
           9   ForumService proxy = (ForumService) Proxy.newProxyInstance(
          10 target.getClass().getClassLoader(),
          11     target.getClass().getInterfaces(),
          12  handler);
          13          //④ 操作代理實例
          14   proxy.removeForum(10);
          15   proxy.removeTopic(1012);
          16  }
          17 }
               
          上面的代碼完成了業(yè)務類代碼和橫切代碼編織和接口代理實例生成的工作,其中在②處,我們將ForumService實例編織為一個包含性能監(jiān)視邏輯的PerformaceHandler實例,然后在③處,通過Proxy的靜態(tài)方法newProxyInstance()為融合了業(yè)務類邏輯和性能監(jiān)視邏輯的handler創(chuàng)建一個ForumService接口的代理實例,該方法的第一個入?yún)轭惣虞d器,第二個入?yún)閯?chuàng)建的代理實例所要實現(xiàn)的一組接口,第三個參數(shù)是整合了業(yè)務邏輯和橫切邏輯的編織器對象。
          按照③處的設置方式,這個代理實例就實現(xiàn)了目標業(yè)務類的所有接口,也即ForumServiceImpl的ForumService接口。這樣,我們就可以按照調(diào)用ForumService接口的實例相同的方式調(diào)用代理實例,如④所示。運行以上的代碼,輸出以下的信息:
              begin monitor
          模擬刪除Forum記錄:10
          end monitor
          com.baobaotao.proxy.ForumServiceImpl.removeForum花費47毫秒。

          begin monitor
          模擬刪除Topic記錄:
          1012
          end monitor
          com.baobaotao.proxy.ForumServiceImpl.removeTopic花費26毫秒。
                
          我們發(fā)現(xiàn),程序的運行效果和直接在業(yè)務類中編寫性能監(jiān)視邏輯的效果一致,但是在這里,原來分散的橫切邏輯代碼已經(jīng)被我們抽取到PerformaceHandler中。當其它業(yè)務類(如UserService、SystemService等)的業(yè)務方法也需要使用性能監(jiān)視時,我們只要按照以上的方式,分別為它們創(chuàng)建代理對象就可以了。下面,我們用時序圖描述調(diào)用關系,進一步代理實例的本質(zhì),如圖1所示:
              

              
            圖 1代理實例的時序圖
              我們在上圖中特別使用虛線陰影的方式對通過代理器創(chuàng)建的ForumService實例進行凸顯,該實例內(nèi)部利用PerformaceHandler整合橫切邏輯和業(yè)務邏輯。調(diào)用者調(diào)用代理對象的的removeForum()和removeTopic()方法時,上圖的內(nèi)部調(diào)用時序清晰地告訴了我們實際上所發(fā)生的一切。



           


          posted on 2011-10-07 19:29 安多 閱讀(905) 評論(0)  編輯  收藏 所屬分類: S2SH Learning
           
          Copyright © 安多 Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 芒康县| 岑溪市| 砚山县| 称多县| 海南省| 阿尔山市| 成都市| 龙里县| 双城市| 仪陇县| 松江区| 平阳县| 龙南县| 莱芜市| 贞丰县| 西贡区| 满洲里市| 大田县| 陈巴尔虎旗| 华亭县| 白河县| 南部县| 讷河市| 徐水县| 乃东县| 虹口区| 基隆市| 汉川市| 深州市| 宁乡县| 金坛市| 碌曲县| 姜堰市| 青川县| 武山县| 襄城县| 华容县| 峨眉山市| 融水| 太原市| 花莲县|