千里冰封
          JAVA 濃香四溢
          posts - 151,comments - 2801,trackbacks - 0
          今天上午寫了一個有關于EJB的攔截例子,其實EJB的攔截用的就是JAVA的代理機制.說廣一點,EJB的實現就是利用代理實現的遠程方法調用.
          EJB會在服務器端生成一個實現了所有的接口的類的代理,然后在里面監聽你所做的所有事情,并與之反應,這樣就實現了遠程調用的效果,你在這邊調用,而EJB容器在別的地方也可以知道你調用了什么,并返回與之對應的結果,這一切都是用代理來實現的.

          下面我們就來認識一下,代理的主要類:java.lang.reflect.Proxy
          它定義了一套靜態方法,供我們使用,其中一個最常用的方法就是生成代理對象
          public static Object newProxyInstance(ClassLoader loader,
                                                Class<?>[] interfaces,
                                                InvocationHandler h)
                                         throws IllegalArgumentException

          它根據你傳入的類加載器和這個代理將會實現的接口,以及一個調用處理器,來生成一個代理對象.說起來比較抽象,還是給點例子吧:
          先聲明一個接口,用來調用代理的方法
          /*
           * MyInterface.java
           *
           * Created on 2007年9月8日, 下午4:38
           *
           * To change this template, choose Tools | Template Manager
           * and open the template in the editor.
           
          */

          package test4;

          /**
           *
           * 
          @author hadeslee
           
          */
          public interface MyInterface {
              
          public void sayHello(String s);
              
          public void doSth();
          }

          然后再寫一個類實現此方法
          /*
           * Test1.java
           *
           * Created on 2007年9月8日, 下午4:31
           *
           * To change this template, choose Tools | Template Manager
           * and open the template in the editor.
           
          */

          package test4;

          import java.lang.reflect.InvocationHandler;
          import java.lang.reflect.Method;
          import java.lang.reflect.Proxy;
          import java.util.ArrayList;
          import java.util.List;


          /**
           *
           * 
          @author hadeslee
           
          */
          public class Test1 implements MyInterface{
              
              
          /** Creates a new instance of Test1 */
              
          public Test1() {
                  
              }
              
              
          public static void main(String[] args) throws Exception{
                  Test1 list
          =new Test1();
                  MyInterface my
          =(MyInterface)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                          list.getClass().getInterfaces(),
                          
          new MyHandler<MyInterface>(list));
                  System.out.println(
          "my.name="+my.getClass().getName());
                  my.doSth();
                  my.sayHello(
          "千里冰封");
              }
              
          //接口中的方法
              public void sayHello(String s) {
                  System.out.println(
          "sayHello to:"+s);
              }
              
          //接口中的方法
              public void doSth() {
                  System.out.println(
          "doSth()");
              }
              
          //一個靜態內部類,實現了InvocationHandler的接口,
              
          //它也是一個關鍵的接口,所有代理后的行為都是在這里實現的
              static class MyHandler<T> implements InvocationHandler{
                  
          private T t;
                  
          public MyHandler(T t){
                      
          this.t=t;
                  }
                  
          //實現方法調用
                  
          //可以自己加上自己的一些調用,此例中只是在加上了一個輸出
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      System.out.println(
          "我知道馬上要被調用的方法是:"+method.getName());
                      
          return method.invoke(t,args);
                  }
                  
              }
          }

          運行上面的類輸出是:

          my.name=$Proxy0
          我知道馬上要被調用的方法是:doSth
          doSth()
          我知道馬上要被調用的方法是:sayHello
          sayHello to:千里冰封

          從這里可以看出,代理的類的名字換成了$Proxy0,其中$Proxy是所有代理類的類名前綴
          我們在調用doSth()和sayHello()的時候,都調用到了我們在代理中設置的輸出.如果你想在這里代理別的類,也是可以的,只要你符合以上的調用規律.
          最后特別要注意的一點是:

          //實現方法調用
                  
          //可以自己加上自己的一些調用,此例中只是在加上了一個輸出
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      System.out.println(
          "我知道馬上要被調用的方法是:"+method.getName());
                      
          return method.invoke(t,args);
                  }

          在上面的實現中,千萬不能調用method.invoke(proxy,args).因為proxy本身就是一個代理的對象,你如果再在它上面調用一個方法的話,會無限遞歸的調用這個方法,所以,在InvocationHandler的實現里面,最好是傳一個代理對象的真正實現進去,這樣就可以還原本來的調用結果,并加上自己的東西在里面.



          盡管千里冰封
          依然擁有晴空

          你我共同品味JAVA的濃香.
          posted on 2007-09-08 18:12 千里冰封 閱讀(6520) 評論(11)  編輯  收藏 所屬分類: JAVASE

          FeedBack:
          # re: JAVA代理機制初探
          2007-09-09 07:07 | sitinspring
          真是不錯,這個方式用對地方了能有很大作為.每天看看Blogjava的首頁更新都能有所收獲,有時還有意外驚喜.  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-09 09:34 | 兵臨城下
          這其實和Spring的AOP是一個概念,實現方法都是一致的  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-09 12:39 | BeanSoft
          呵呵, 確切說 AOP 的底層實現應該是用代理. 基本上大部分的連接池啊啥的都用代理來做了. 方法攔截(Interceptors)本質上也是代理.  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 00:04 | 楊愛友
          @BeanSoft
          有了spring的 aop不知道方法攔截還有什么必要,AOP完全可以實現方法攔截啊。  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 02:12 | yexiaozi
          (1)生成代理對象:
          MyInterface my=(MyInterface)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
          list.getClass().getInterfaces(),
          new MyHandler<MyInterface>(list));
          (2)然后怎么調用 invoke(*,*,*)?
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          System.out.println("我知道馬上要被調用的方法是:"+method.getName());
          return method.invoke(t,args);
          }
          樓主,給個答復看???????????????????????????????????????????  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 02:14 | yexiaozi
          樓主:你能否把代碼調用的流程,幫我解釋下(越詳細越好),偶剛接觸代理,
          麻煩了!辛苦了!謝謝了!  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 14:37 | 千里冰封
          @yexiaozi
          關于invoke的使用方法如下:
          invoke(Object obj, Object... args)
          對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。
          第一個obj表示你要調用哪個對象上的方法,后面的可變參數表示你傳入的參數列表
            回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 14:38 | 千里冰封
          @yexiaozi
          生成了代理對象之后,代理對象會自動攔截你對方法的調用,而調用你在InvokcationHandler里面定義的invoke方法,從而實現所有調用的方法對你來說都是可知道的  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 16:05 | 黑盒子
          盼望后續深入研究~~~~~  回復  更多評論
            
          # re: JAVA代理機制初探
          2007-09-16 22:29 | yexiaozi
          謝謝樓主!好幾天沒來看了?今天發現樓主回復了!
          理解了一點哦!  回復  更多評論
            
          # re: JAVA代理機制初探[未登錄]
          2008-09-22 10:28 | ben
          不錯,謝謝樓主分享。  回復  更多評論
            
          主站蜘蛛池模板: 巫山县| 科尔| 扎赉特旗| 秭归县| 天峻县| 安国市| 阜宁县| 民县| 东宁县| 疏勒县| 麦盖提县| 石柱| 革吉县| 易门县| 新邵县| 新绛县| 商洛市| 高要市| 新竹县| 辰溪县| 汪清县| 宽甸| 瑞安市| 永宁县| 南投市| 清水河县| 东兰县| 墨竹工卡县| 神池县| 樟树市| 黄石市| 随州市| 无锡市| 茌平县| 许昌市| 新余市| 伊金霍洛旗| 丰镇市| 红原县| 新泰市| 固安县|