最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
InvocationHandler中invoke()方法的調(diào)用問題分析

Java中動(dòng)態(tài)代理的實(shí)現(xiàn),關(guān)鍵就是這兩個(gè)東西:Proxy、InvocationHandler,下面從InvocationHandler接口中的invoke方法入手,簡(jiǎn)單說(shuō)明一下Java如何實(shí)現(xiàn)動(dòng)態(tài)代理的。

成都創(chuàng)新互聯(lián)主營(yíng)隨州網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營(yíng)網(wǎng)站建設(shè)方案,成都App制作,隨州h5小程序開發(fā)搭建,隨州網(wǎng)站營(yíng)銷推廣歡迎隨州等地區(qū)企業(yè)咨詢

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

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

首先猜測(cè)一下,method是調(diào)用的方法,即需要執(zhí)行的方法;args是方法的參數(shù);proxy,這個(gè)參數(shù)是什么?以上invoke()方法的實(shí)現(xiàn)即是比較標(biāo)準(zhǔn)的形式,我們看到,這里并沒有用到proxy參數(shù)。查看JDK文檔中Proxy的說(shuō)明,如下:

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. 

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

為了方便說(shuō)明,這里寫一個(gè)簡(jiǎn)單的例子來(lái)實(shí)現(xiàn)動(dòng)態(tài)代理。

//抽象角色(動(dòng)態(tài)代理只能代理接口) 
public interface Subject { 
   
  public void request(); 
} 
//真實(shí)角色:實(shí)現(xiàn)了Subject的request()方法 
public class RealSubject implements Subject{ 
   
  public void request(){ 
    System.out.println("From real subject."); 
  } 
} 
//實(shí)現(xiàn)了InvocationHandler 
public class DynamicSubject implements InvocationHandler 
{ 
  private Object obj;//這是動(dòng)態(tài)代理的好處,被封裝的對(duì)象是Object類型,接受任意類型的對(duì)象 
 
  public DynamicSubject() 
  { 
  } 
 
  public DynamicSubject(Object obj) 
  { 
    this.obj = obj; 
  } 
 
  //這個(gè)方法不是我們顯示的去調(diào)用 
  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; 
  } 
 
} 
//客戶端:生成代理實(shí)例,并調(diào)用了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); 
     
    //這里可以通過(guò)運(yùn)行結(jié)果證明subject是Proxy的一個(gè)實(shí)例,這個(gè)實(shí)例實(shí)現(xiàn)了Subject接口 
    System.out.println(subject instanceof Proxy); 
     
    //這里可以看出subject的Class類是$Proxy0,這個(gè)$Proxy0類繼承了Proxy,實(shí)現(xiàn)了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實(shí)現(xiàn)的接口是:"); 
     
    Class<?>[] interfaces=subject.getClass().getInterfaces(); 
     
    for(Class<?> i:interfaces){ 
      System.out.print(i.getName()+", "); 
    } 
 
    System.out.println("\n\n"+"運(yùn)行結(jié)果為:"); 
    subject.request(); 
  } 
} 

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

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

PS:這個(gè)結(jié)果的信息非常重要,至少對(duì)我來(lái)說(shuō)。因?yàn)槲以趧?dòng)態(tài)代理犯暈的根源就在于將上面的subject.request()理解錯(cuò)了,至少是被表面所迷惑,沒有發(fā)現(xiàn)這個(gè)subject和Proxy之間的聯(lián)系,一度糾結(jié)于最后調(diào)用的這個(gè)request()是怎么和invoke()聯(lián)系上的,而invoke又是怎么知道request存在的。其實(shí)上面的true和class$Proxy0就能解決很多的疑問,再加上下面將要說(shuō)的$Proxy0的源碼,完全可以解決動(dòng)態(tài)代理的疑惑了。

從以上代碼和結(jié)果可以看出,我們并沒有顯示的調(diào)用invoke()方法,但是這個(gè)方法確實(shí)執(zhí)行了。下面就整個(gè)的過(guò)程進(jìn)行分析一下:

從Client中的代碼看,可以從newProxyInstance這個(gè)方法作為突破口,我們先來(lái)看一下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類型的構(gòu)造方法 
      */ 
    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)根據(jù)參數(shù)loader和interfaces調(diào)用方法 getProxyClass(loader, interfaces)創(chuàng)建代理類$Proxy0.$Proxy0類 實(shí)現(xiàn)了interfaces的接口,并繼承了Proxy類.
(2)實(shí)例化$Proxy0并在構(gòu)造方法中把DynamicSubject傳過(guò)去,接著$Proxy0調(diào)用父類Proxy的構(gòu)造器,為h賦值,如下:

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

來(lái)看一下這個(gè)繼承了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實(shí)例強(qiáng)制轉(zhuǎn)換成Subject,并將引用賦給subject。當(dāng)執(zhí)行subject.request()方法時(shí),就調(diào)用了$Proxy0類中的request()方法,進(jìn)而調(diào)用父類Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

PS:1、需要說(shuō)明的一點(diǎn)是,Proxy類中g(shù)etProxyClass方法返回的是Proxy的Class類。之所以說(shuō)明,是因?yàn)槲乙婚_始犯了個(gè)低級(jí)錯(cuò)誤,以為返回的是“被代理類的Class類”--!推薦看一下getProxyClass的源碼,很長(zhǎng)=。=

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

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

A:就本人目前的水平看來(lái),這個(gè)proxy參數(shù)并沒有什么作用,在整個(gè)動(dòng)態(tài)代理機(jī)制中,并沒有用到InvocationHandler中invoke方法的proxy參數(shù)。而傳入的這個(gè)參數(shù)實(shí)際是代理類的一個(gè)實(shí)例。我想可能是為了讓程序員在invoke方法中使用反射來(lái)獲取關(guān)于代理類的一些信息吧。

總結(jié)

以上就是本文關(guān)于InvocationHandler中invoke()方法的調(diào)用問題分析的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:

Spring靜態(tài)代理和動(dòng)態(tài)代理代碼詳解

Spring框架依賴注入方法示例

Java編程實(shí)現(xiàn)springMVC簡(jiǎn)單登錄實(shí)例

如有不足之處,歡迎留言指出。


本文標(biāo)題:InvocationHandler中invoke()方法的調(diào)用問題分析
網(wǎng)站路徑:http://fisionsoft.com.cn/article/iggopg.html