溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 動態(tài)代理中Proxy的使用方法

發(fā)布時間:2021-10-29 16:32:27 來源:億速云 閱讀:188 作者:柒染 欄目:編程語言

本篇文章給大家分享的是有關Java 動態(tài)代理中Proxy的使用方法,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

?動態(tài)代理可以提供對另一個對象的訪問,同時隱藏實際對象的具體事實,代理對象對客戶隱藏了實際對象。動態(tài)代理可以對請求進行其他的一些處理,在不允許直接訪問某些類,或需要對訪問做一些特殊處理等,這時候可以考慮使用代理。目前 Java 開發(fā)包中提供了對動態(tài)代理的支持,但現(xiàn)在只支持對接口的實現(xiàn)。

主要是通過 java.lang.reflect.Proxy 類和 java.lang.reflect.InvocationHandler 接口。 Proxy 類主要用來獲取動態(tài)代理對象,InvocationHandler 接口用來約束調(diào)用者行為。

“寫一個 ArrayList 類的代理,其內(nèi)部實現(xiàn)和 ArrayList 中完全相同的功能,并可以計算每個方法運行的時間?!边@是一份考題上的題目,沒有答案,來看下實現(xiàn):

package example;  import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.lang.reflect.Proxy;  import java.util.ArrayList;  import java.util.List;  import java.util.concurrent.TimeUnit;  /**   * -----------------------------------------   * @描述  TODO   * @作者  fancy   * @郵箱  fancydeepin@yeah.net   * @日期  2012-8-27 <p>   * -----------------------------------------   */ public class ProxyApp {        public static void main(String[] args){                    //ArrayList代理,通過代理計算每個方法調(diào)用所需時間          List<Integer> arrayListProxy = (List<Integer>)Proxy.newProxyInstance(              ArrayList.class.getClassLoader(),   /*定義代理類的類加載器,用于創(chuàng)建代理對象,不一定必須是ArrayList,也可以是其他的類加載器*/             ArrayList.class.getInterfaces(),     /*代理類要實現(xiàn)的接口列表*/             new InvocationHandler() {            /*指派方法調(diào)用的調(diào)用處理程序,這里用了匿名內(nèi)部類*/                                   private ArrayList<Integer> target = new ArrayList<Integer>(); //目標對象(真正操作的對象)                  /**                   * <B>方法描述:</B>                   * <p style="margin-left:20px;color:#A52A2A;">                   * 在代理實例上處理方法調(diào)用并返回結果                   * @param proxy     代理對象(注意不是目標對象)                   * @param method  被代理的方法                   * @param args         被代理的方法的參數(shù)集                   * @return <span style="color: #008080;"> 返回方法調(diào)用結果 </span>                   */                 @Override                 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                                            long beginTime = System.currentTimeMillis();  //開始時間                      TimeUnit.MICROSECONDS.sleep(1);                      Object obj = method.invoke(target, args);          //實際調(diào)用的方法,并接受方法的返回值                      long endTime = System.currentTimeMillis();   //結束時間                      System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");                      return obj;   //返回實際調(diào)用的方法的返回值                                        }                                }          );          arrayListProxy.add(2);          arrayListProxy.add(4);          System.out.println("--------- 迭代 ---------");          for(int i : arrayListProxy){              System.out.print(i + "\t");          }      }  }

后臺打印輸出結果:

 [add] spend 2 ms
[add] spend 1 ms
--------- 迭代 ---------
[iterator] spend 1 ms
2 4

從代碼上來看,用到了匿名內(nèi)部類,這樣一來,InvocationHandler 只能用一次,如果多個地方都需要用到這樣一個相同的 InvocationHandler,可以將其抽象出來成為一個單獨的類:

package test;  import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.util.concurrent.TimeUnit;  public class MyInvocationHandler implements InvocationHandler{      private Object target; //目標對象          public MyInvocationHandler(Object target){          this.target = target;      }      @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                  long beginTime = System.currentTimeMillis();          TimeUnit.MICROSECONDS.sleep(1);          Object obj = method.invoke(target, args);          long endTime = System.currentTimeMillis();          System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");          return obj;          }  }

客戶端調(diào)用改成:

package example;  import java.lang.reflect.Proxy;  import java.util.ArrayList;  import java.util.List;  /**   * -----------------------------------------   * @描述  TODO   * @作者  fancy   * @郵箱  fancydeepin@yeah.net   * @日期  2012-8-27 <p>   * -----------------------------------------   */ public class ProxyApp {      public static void main(String[] args){                  //ArrayList代理,通過代理計算每個方法調(diào)用所需時間          List<Integer> arrayListProxy = (List<Integer>)Proxy.newProxyInstance(              ArrayList.class.getClassLoader(),     /*定義代理類的類加載器,用于創(chuàng)建代理對象,不一定必須是ArrayList,也可以是其他的類加載器*/             ArrayList.class.getInterfaces(),       /*代理類要實現(xiàn)的接口列表*/             new MyInvocationHandler(new ArrayList<Integer>())         /*指派方法調(diào)用的調(diào)用處理程序,這里用了匿名內(nèi)部類*/         );          arrayListProxy.add(2);          arrayListProxy.add(4);          System.out.println("--------- 迭代 ---------");          for(int i : arrayListProxy){              System.out.print(i + "\t");          }      }  }

從上面代碼看來,客戶端知道代理的實際目標對象,還知道怎么樣去創(chuàng)建這樣一個代理對象,如果想把這些信息全部對客戶端隱藏起來,可以將這些代碼挪到一個類中,將它們封裝起來:

package example;  import java.lang.reflect.InvocationHandler;  import java.lang.reflect.Method;  import java.lang.reflect.Proxy;  import java.util.ArrayList;  import java.util.List;  import java.util.concurrent.TimeUnit;  /**   * -----------------------------------------   * @描述  TODO   * @作者  fancy   * @郵箱  fancydeepin@yeah.net   * @日期  2012-8-27 <p>   * -----------------------------------------   */ public class ProxyUtil {      public enum ArrayListProxy {          PROXY;               private Object target;            ArrayListProxy(){              this.target = new ArrayList<Object>();          }          public List getInstance(){                            return (List)Proxy.newProxyInstance(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces(),                      new InvocationHandler() {                             @Override                         public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                                                            long beginTime = System.currentTimeMillis();                              TimeUnit.MICROSECONDS.sleep(1);                              Object obj = method.invoke(target, args);                              long endTime = System.currentTimeMillis();                              System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");                              return obj;                           }                      });          }      }  }

客戶端調(diào)用改成:

package example;  import java.util.List;  import example.ProxyUtil.ArrayListProxy;  /**   * -----------------------------------------   * @描述  TODO   * @作者  fancy   * @郵箱  fancydeepin@yeah.net   * @日期  2012-8-27 <p>   * -----------------------------------------   */ public class ProxyApp {      public static void main(String[] args){          List<Integer> arrayListProxy = ArrayListProxy.PROXY.getInstance();          arrayListProxy.add(2);          arrayListProxy.add(4);          System.out.println("--------- 迭代 ---------");          for(int i : arrayListProxy){              System.out.print(i + "\t");          }      }  }

上面代碼中用到了枚舉 enum,如果不想用枚舉,就改用普通類來實現(xiàn)就行了。

以上就是Java 動態(tài)代理中Proxy的使用方法,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學到更多知識。更多詳情敬請關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI