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

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

          它根據(jù)你傳入的類加載器和這個代理將會實現(xiàn)的接口,以及一個調(diào)用處理器,來生成一個代理對象.說起來比較抽象,還是給點例子吧:
          先聲明一個接口,用來調(diào)用代理的方法
          /*
           * 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();
          }

          然后再寫一個類實現(xiàn)此方法
          /*
           * 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()");
              }
              
          //一個靜態(tài)內(nèi)部類,實現(xiàn)了InvocationHandler的接口,
              
          //它也是一個關(guān)鍵的接口,所有代理后的行為都是在這里實現(xiàn)的
              static class MyHandler<T> implements InvocationHandler{
                  
          private T t;
                  
          public MyHandler(T t){
                      
          this.t=t;
                  }
                  
          //實現(xiàn)方法調(diào)用
                  
          //可以自己加上自己的一些調(diào)用,此例中只是在加上了一個輸出
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                      System.out.println(
          "我知道馬上要被調(diào)用的方法是:"+method.getName());
                      
          return method.invoke(t,args);
                  }
                  
              }
          }

          運行上面的類輸出是:

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

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

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

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



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

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

          FeedBack:
          # re: JAVA代理機制初探
          2007-09-09 07:07 | sitinspring
          真是不錯,這個方式用對地方了能有很大作為.每天看看Blogjava的首頁更新都能有所收獲,有時還有意外驚喜.  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-09 09:34 | 兵臨城下
          這其實和Spring的AOP是一個概念,實現(xiàn)方法都是一致的  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-09 12:39 | BeanSoft
          呵呵, 確切說 AOP 的底層實現(xiàn)應(yīng)該是用代理. 基本上大部分的連接池啊啥的都用代理來做了. 方法攔截(Interceptors)本質(zhì)上也是代理.  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 00:04 | 楊愛友
          @BeanSoft
          有了spring的 aop不知道方法攔截還有什么必要,AOP完全可以實現(xiàn)方法攔截啊。  回復(fù)  更多評論
            
          # 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)然后怎么調(diào)用 invoke(*,*,*)?
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          System.out.println("我知道馬上要被調(diào)用的方法是:"+method.getName());
          return method.invoke(t,args);
          }
          樓主,給個答復(fù)看???????????????????????????????????????????  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 02:14 | yexiaozi
          樓主:你能否把代碼調(diào)用的流程,幫我解釋下(越詳細越好),偶剛接觸代理,
          麻煩了!辛苦了!謝謝了!  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 14:37 | 千里冰封
          @yexiaozi
          關(guān)于invoke的使用方法如下:
          invoke(Object obj, Object... args)
          對帶有指定參數(shù)的指定對象調(diào)用由此 Method 對象表示的底層方法。
          第一個obj表示你要調(diào)用哪個對象上的方法,后面的可變參數(shù)表示你傳入的參數(shù)列表
            回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 14:38 | 千里冰封
          @yexiaozi
          生成了代理對象之后,代理對象會自動攔截你對方法的調(diào)用,而調(diào)用你在InvokcationHandler里面定義的invoke方法,從而實現(xiàn)所有調(diào)用的方法對你來說都是可知道的  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-10 16:05 | 黑盒子
          盼望后續(xù)深入研究~~~~~  回復(fù)  更多評論
            
          # re: JAVA代理機制初探
          2007-09-16 22:29 | yexiaozi
          謝謝樓主!好幾天沒來看了?今天發(fā)現(xiàn)樓主回復(fù)了!
          理解了一點哦!  回復(fù)  更多評論
            
          # re: JAVA代理機制初探[未登錄]
          2008-09-22 10:28 | ben
          不錯,謝謝樓主分享。  回復(fù)  更多評論
            
          主站蜘蛛池模板: 南江县| 潍坊市| 古浪县| 永济市| 友谊县| 古蔺县| 祁阳县| 海安县| 缙云县| 瑞昌市| 新余市| 龙口市| 舞钢市| 嫩江县| 五台县| 轮台县| 什邡市| 景德镇市| 富锦市| 平乡县| 布尔津县| 建始县| 泊头市| 贵州省| 鄂伦春自治旗| 溧阳市| 山阳县| 杭锦旗| 新化县| 永登县| 南皮县| 武陟县| 永靖县| 齐齐哈尔市| 黔江区| 万州区| 宜章县| 常宁市| 兴山县| 武宁县| 长岭县|