亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

InvocationHandler中invoke()方法的調用問題分析

2024-07-13 10:13:38
字體:
來源:轉載
供稿:網友

Java中動態代理的實現,關鍵就是這兩個東西:Proxy、InvocationHandler,下面從InvocationHandler接口中的invoke方法入手,簡單說明一下Java如何實現動態代理的。

首先,invoke方法的完整形式如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   {	method.invoke(obj, args);	return null;}

首先猜測一下,method是調用的方法,即需要執行的方法;args是方法的參數;proxy,這個參數是什么?以上invoke()方法的實現即是比較標準的形式,我們看到,這里并沒有用到proxy參數。查看JDK文檔中Proxy的說明,如下:

A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments. 

由此可以知道以上的猜測是正確的,同時也知道,proxy參數傳遞的即是代理類的實例。

為了方便說明,這里寫一個簡單的例子來實現動態代理。

//抽象角色(動態代理只能代理接口) public interface Subject {      public void request(); } 
//真實角色:實現了Subject的request()方法 public class RealSubject implements Subject{      public void request(){     System.out.println("From real subject.");   } } 
//實現了InvocationHandler public class DynamicSubject implements InvocationHandler {   private Object obj;//這是動態代理的好處,被封裝的對象是Object類型,接受任意類型的對象    public DynamicSubject()   {   }    public DynamicSubject(Object obj)   {     this.obj = obj;   }    //這個方法不是我們顯示的去調用   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable   {     System.out.println("before calling " + method);      method.invoke(obj, args);      System.out.println("after calling " + method);      return null;   }  } 
//客戶端:生成代理實例,并調用了request()方法 public class Client {    public static void main(String[] args) throws Throwable{     // TODO Auto-generated method stub      Subject rs=new RealSubject();//這里指定被代理類     InvocationHandler ds=new DynamicSubject(rs);     Class<?> cls=rs.getClass();          //以下是一次性生成代理          Subject subject=(Subject) Proxy.newProxyInstance(         cls.getClassLoader(),cls.getInterfaces(), ds);          //這里可以通過運行結果證明subject是Proxy的一個實例,這個實例實現了Subject接口     System.out.println(subject instanceof Proxy);          //這里可以看出subject的Class類是$Proxy0,這個$Proxy0類繼承了Proxy,實現了Subject接口     System.out.println("subject的Class類是:"+subject.getClass().toString());          System.out.print("subject中的屬性有:");          Field[] field=subject.getClass().getDeclaredFields();     for(Field f:field){       System.out.print(f.getName()+", ");     }          System.out.print("/n"+"subject中的方法有:");          Method[] method=subject.getClass().getDeclaredMethods();          for(Method m:method){       System.out.print(m.getName()+", ");     }          System.out.println("/n"+"subject的父類是:"+subject.getClass().getSuperclass());          System.out.print("/n"+"subject實現的接口是:");          Class<?>[] interfaces=subject.getClass().getInterfaces();          for(Class<?> i:interfaces){       System.out.print(i.getName()+", ");     }      System.out.println("/n/n"+"運行結果為:");     subject.request();   } } 

運行結果如下:此處省略了包名,***代替
true
subject的Class類是:class $Proxy0
subject中的屬性有:m1, m3, m0, m2,
subject中的方法有:request, hashCode, equals, toString,
subject的父類是:class java.lang.reflect.Proxy
subject實現的接口是:cn.edu.ustc.dynamicproxy.Subject,

運行結果為:
before calling public abstract void ***.Subject.request()
From real subject.
after calling public abstract void ***.Subject.request()

PS:這個結果的信息非常重要,至少對我來說。因為我在動態代理犯暈的根源就在于將上面的subject.request()理解錯了,至少是被表面所迷惑,沒有發現這個subject和Proxy之間的聯系,一度糾結于最后調用的這個request()是怎么和invoke()聯系上的,而invoke又是怎么知道request存在的。其實上面的true和class$Proxy0就能解決很多的疑問,再加上下面將要說的$Proxy0的源碼,完全可以解決動態代理的疑惑了。

從以上代碼和結果可以看出,我們并沒有顯示的調用invoke()方法,但是這個方法確實執行了。下面就整個的過程進行分析一下:

從Client中的代碼看,可以從newProxyInstance這個方法作為突破口,我們先來看一下Proxy類中newProxyInstance方法的源代碼:

public static Object newProxyInstance(ClassLoader loader,     Class<?>[] interfaces,     InvocationHandler h) throws IllegalArgumentException {   if (h == null) {     throw new NullPointerException();   }    /*    * Look up or generate the designated proxy class.    */   Class cl = getProxyClass(loader, interfaces);    /*    * Invoke its constructor with the designated invocation handler.    */   try {       /*       * Proxy源碼開始有這樣的定義:       * private final static Class[] constructorParams = { InvocationHandler.class };       * cons即是形參為InvocationHandler類型的構造方法       */     Constructor cons = cl.getConstructor(constructorParams);     return (Object) cons.newInstance(new Object[] { h });   } catch (NoSuchMethodException e) {     throw new InternalError(e.toString());   } catch (IllegalAccessException e) {     throw new InternalError(e.toString());   } catch (InstantiationException e) {     throw new InternalError(e.toString());   } catch (InvocationTargetException e) {     throw new InternalError(e.toString());   } } 

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下幾件事.
(1)根據參數loader和interfaces調用方法 getProxyClass(loader, interfaces)創建代理類$Proxy0.$Proxy0類 實現了interfaces的接口,并繼承了Proxy類.
(2)實例化$Proxy0并在構造方法中把DynamicSubject傳過去,接著$Proxy0調用父類Proxy的構造器,為h賦值,如下:

class Proxy{   InvocationHandler h=null;   protected Proxy(InvocationHandler h) {     this.h = h;   }   ... } 

來看一下這個繼承了Proxy的$Proxy0的源代碼:

public final class $Proxy0 extends Proxy implements Subject {   private static Method m1;   private static Method m0;   private static Method m3;   private static Method m2;    static {     try {       m1 = Class.forName("java.lang.Object").getMethod("equals",           new Class[] { Class.forName("java.lang.Object") });        m0 = Class.forName("java.lang.Object").getMethod("hashCode",           new Class[0]);        m3 = Class.forName("***.RealSubject").getMethod("request",           new Class[0]);        m2 = Class.forName("java.lang.Object").getMethod("toString",           new Class[0]);      } catch (NoSuchMethodException nosuchmethodexception) {       throw new NoSuchMethodError(nosuchmethodexception.getMessage());     } catch (ClassNotFoundException classnotfoundexception) {       throw new NoClassDefFoundError(classnotfoundexception.getMessage());     }   } //static    public $Proxy0(InvocationHandler invocationhandler) {     super(invocationhandler);   }    @Override   public final boolean equals(Object obj) {     try {       return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();     } catch (Throwable throwable) {       throw new UndeclaredThrowableException(throwable);     }   }    @Override   public final int hashCode() {     try {       return ((Integer) super.h.invoke(this, m0, null)).intValue();     } catch (Throwable throwable) {       throw new UndeclaredThrowableException(throwable);     }   }    public final void request() {     try {       super.h.invoke(this, m3, null);       return;     } catch (Error e) {     } catch (Throwable throwable) {       throw new UndeclaredThrowableException(throwable);     }   }    @Override   public final String toString() {     try {       return (String) super.h.invoke(this, m2, null);     } catch (Throwable throwable) {       throw new UndeclaredThrowableException(throwable);     }   } } 

接著把得到的$Proxy0實例強制轉換成Subject,并將引用賦給subject。當執行subject.request()方法時,就調用了$Proxy0類中的request()方法,進而調用父類Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

PS:1、需要說明的一點是,Proxy類中getProxyClass方法返回的是Proxy的Class類。之所以說明,是因為我一開始犯了個低級錯誤,以為返回的是“被代理類的Class類”--!推薦看一下getProxyClass的源碼,很長=。=

2、從$Proxy0的源碼可以看出,動態代理類不僅代理了顯示定義的接口中的方法,而且還代理了java的根類Object中的繼承而來的equals()、hashcode()、toString()這三個方法,并且僅此三個方法。

Q:到現在為止,還有一個疑問,invoke方法中的第一個參數是Proxy的實例(準確說,最終用到的是$Proxy0的實例),但是有什么用呢?或者說,程序內是怎樣顯示出作用的?

A:就本人目前的水平看來,這個proxy參數并沒有什么作用,在整個動態代理機制中,并沒有用到InvocationHandler中invoke方法的proxy參數。而傳入的這個參數實際是代理類的一個實例。我想可能是為了讓程序員在invoke方法中使用反射來獲取關于代理類的一些信息吧。

總結

以上就是本文關于InvocationHandler中invoke()方法的調用問題分析的全部內容,希望對大家有所幫助。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91精品视频在线看| 国产精品久久久久aaaa九色| 国产日韩欧美成人| 精品久久久久久久久久久久| 在线激情影院一区| 日韩欧美亚洲综合| 久久免费少妇高潮久久精品99| 日韩av免费在线播放| 在线激情影院一区| 亚洲最大的免费| 2019av中文字幕| 久久久久久18| 亚洲日韩中文字幕在线播放| 91免费国产网站| 日韩中文在线中文网三级| 精品偷拍各种wc美女嘘嘘| 不卡在线观看电视剧完整版| 欧美日韩国产第一页| 成人黄色影片在线| 亚洲午夜精品久久久久久久久久久久| 青草成人免费视频| 亚洲免费视频观看| 97久久国产精品| xvideos亚洲人网站| 国产精品久久久久久影视| 亚洲国产天堂网精品网站| 色多多国产成人永久免费网站| 在线免费看av不卡| 欧美激情精品久久久久久免费印度| 超碰精品一区二区三区乱码| 欧美在线中文字幕| 亚洲自拍欧美色图| 亚洲一级黄色av| 成人免费在线视频网址| 亚洲国产古装精品网站| 26uuu另类亚洲欧美日本老年| 精品久久久久久久中文字幕| 久久影视电视剧免费网站清宫辞电视| 国产日韩欧美在线视频观看| 国产精品丝袜白浆摸在线| 欧美激情亚洲自拍| 亚洲一区二区三区久久| 亚洲国产日韩欧美在线99| 日韩成人xxxx| 日韩欧美aⅴ综合网站发布| 国语自产偷拍精品视频偷| 欧美老女人在线视频| 91精品国产色综合久久不卡98| 韩国精品久久久999| 亚洲免费一在线| 日韩电影免费在线观看中文字幕| 国产精品网站大全| 国产美女久久精品香蕉69| 亚洲男人7777| 国产一区二区三区四区福利| 黑丝美女久久久| 精品国产一区二区三区久久久| 亚洲国产欧美久久| 7m精品福利视频导航| 欧美日韩精品在线观看| 国产aⅴ夜夜欢一区二区三区| 精品久久久国产| 亚洲欧美精品一区二区| 26uuu日韩精品一区二区| 欧美一区二粉嫩精品国产一线天| 亚洲第一区第一页| 日韩一区在线视频| 欧美国产视频日韩| 视频一区视频二区国产精品| 亚洲精品98久久久久久中文字幕| 成人黄色免费片| 久久精品99久久久久久久久| 国产精品嫩草视频| 91色在线视频| 性欧美视频videos6一9| 日韩在线视频播放| 91精品在线看| 色综合色综合久久综合频道88| 伊是香蕉大人久久| 色综合久久中文字幕综合网小说| 亚洲韩国日本中文字幕| 亚洲精品成人av| 久久久久久久久久亚洲| 亚洲精品成人av| 欧美性色xo影院| 亚洲国产精品yw在线观看| 国产精品国产亚洲伊人久久| 日本亚洲欧洲色α| 国产精品成人国产乱一区| 亚洲精品国产精品国自产观看浪潮| 日韩av中文字幕在线播放| 国产性猛交xxxx免费看久久| 亚洲一区二区久久久久久久| 欧美日韩国产色| 久久久久久噜噜噜久久久精品| 欧美精品一区在线播放| 久久国产精品视频| 国产在线一区二区三区| 亚洲国产日韩欧美在线99| 欧美乱妇40p| 日本成人黄色片| 国模精品系列视频| 在线亚洲欧美视频| 欧美黄色三级网站| 欧美成人在线影院| 亚洲第一福利视频| 国产在线播放不卡| 国产成人在线亚洲欧美| 午夜精品国产精品大乳美女| 欧美精品激情在线观看| 日韩在线欧美在线| 成人激情免费在线| 在线精品高清中文字幕| 久久好看免费视频| 国产精品流白浆视频| 97久久伊人激情网| 久久精品一本久久99精品| 亚洲欧美变态国产另类| 亚洲a∨日韩av高清在线观看| 亚洲一区二区少妇| 成人免费视频a| 国产乱肥老妇国产一区二| 久久久精品日本| 中文字幕在线观看日韩| 在线观看欧美www| 亚洲999一在线观看www| 国产女同一区二区| 久久精品99久久香蕉国产色戒| 69国产精品成人在线播放| 亚洲福利视频免费观看| 欧美性色视频在线| 日本成人激情视频| 热99久久精品| 亚洲欧洲av一区二区| 欧美激情一级精品国产| 欧美激情影音先锋| 亚洲激情在线观看视频免费| 国产成人精品综合久久久| 欧美色图在线视频| 69精品小视频| 亚洲视频欧美视频| 岛国av一区二区三区| 亚洲成在人线av| 亚洲自拍小视频| 亚洲精品电影在线观看| 国产区亚洲区欧美区| 欧美在线影院在线视频| 最近免费中文字幕视频2019| 亚洲色图美腿丝袜| 色偷偷噜噜噜亚洲男人的天堂| 九九热这里只有精品6| 久久久在线免费观看| www.欧美视频| 欧美日韩在线第一页| 这里只有精品在线播放| 麻豆成人在线看| 亚洲精品色婷婷福利天堂| 国语自产偷拍精品视频偷| 久久久精品一区二区三区| 国产亚洲精品va在线观看| 全球成人中文在线| 欧美性猛交xxxx乱大交极品| 欧美激情精品久久久久久蜜臀| 精品高清一区二区三区|