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

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

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

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

          運(yùn)行上面的類輸出是:

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

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

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

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



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

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

          FeedBack:
          # re: JAVA代理機(jī)制初探
          2007-09-09 07:07 | sitinspring
          真是不錯(cuò),這個(gè)方式用對(duì)地方了能有很大作為.每天看看Blogjava的首頁(yè)更新都能有所收獲,有時(shí)還有意外驚喜.  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-09 09:34 | 兵臨城下
          這其實(shí)和Spring的AOP是一個(gè)概念,實(shí)現(xiàn)方法都是一致的  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-09 12:39 | BeanSoft
          呵呵, 確切說(shuō) AOP 的底層實(shí)現(xiàn)應(yīng)該是用代理. 基本上大部分的連接池啊啥的都用代理來(lái)做了. 方法攔截(Interceptors)本質(zhì)上也是代理.  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 00:04 | 楊愛友
          @BeanSoft
          有了spring的 aop不知道方法攔截還有什么必要,AOP完全可以實(shí)現(xiàn)方法攔截啊。  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 02:12 | yexiaozi
          (1)生成代理對(duì)象:
          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);
          }
          樓主,給個(gè)答復(fù)看???????????????????????????????????????????  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 02:14 | yexiaozi
          樓主:你能否把代碼調(diào)用的流程,幫我解釋下(越詳細(xì)越好),偶剛接觸代理,
          麻煩了!辛苦了!謝謝了!  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 14:37 | 千里冰封
          @yexiaozi
          關(guān)于invoke的使用方法如下:
          invoke(Object obj, Object... args)
          對(duì)帶有指定參數(shù)的指定對(duì)象調(diào)用由此 Method 對(duì)象表示的底層方法。
          第一個(gè)obj表示你要調(diào)用哪個(gè)對(duì)象上的方法,后面的可變參數(shù)表示你傳入的參數(shù)列表
            回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 14:38 | 千里冰封
          @yexiaozi
          生成了代理對(duì)象之后,代理對(duì)象會(huì)自動(dòng)攔截你對(duì)方法的調(diào)用,而調(diào)用你在InvokcationHandler里面定義的invoke方法,從而實(shí)現(xiàn)所有調(diào)用的方法對(duì)你來(lái)說(shuō)都是可知道的  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-10 16:05 | 黑盒子
          盼望后續(xù)深入研究~~~~~  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探
          2007-09-16 22:29 | yexiaozi
          謝謝樓主!好幾天沒(méi)來(lái)看了?今天發(fā)現(xiàn)樓主回復(fù)了!
          理解了一點(diǎn)哦!  回復(fù)  更多評(píng)論
            
          # re: JAVA代理機(jī)制初探[未登錄](méi)
          2008-09-22 10:28 | ben
          不錯(cuò),謝謝樓主分享。  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 连城县| 天镇县| 惠安县| 壶关县| 平果县| 长宁区| 洛川县| 深水埗区| 涞水县| 瑞安市| 县级市| 长海县| 津市市| 梁平县| 通山县| 南木林县| 祥云县| 桐梓县| 玉树县| 苏尼特右旗| 龙山县| 桂林市| 新密市| 宝清县| 曲周县| 德江县| 舟山市| 镇安县| 大邑县| 肇庆市| 徐汇区| 甘孜县| 大同市| 杨浦区| 改则县| 时尚| 静海县| 延寿县| 鄢陵县| 通山县| 余庆县|