日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jdk动态代理invoke方法自动运行原因

發布時間:2024/1/1 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jdk动态代理invoke方法自动运行原因 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

invoke 方法介紹

想要知道 invoke方法為什么會自動調用我們先要來了解一下這個方法 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args)首先 該方法來自于接口InvocationHandler ,該接口中僅有一個invoke方法 ,該方法中有三個參數 * @param proxy the proxy instance that the method was invoked 這是接口源碼注釋中對第一個參數proxy的解釋:方法被調用的代理實例 我們可以認為它就是一個代理實例但是代理又是什么呢?這時候可能有小伙伴蒙了。 代理實例其實是代理類本身的一個實例,下面是我自己寫的一個動態代理小案例這是一個接口,動態代理必須有一個接口的存在 public interface PorxyInte {public void test(); } 這是一個實現了接口的實現類,寫的有些簡便,主要看起來清晰 public class ProImp implements PorxyInte {@Overridepublic void test() {System.out.println("test");} }

這是測試類 通過了Proxy.newProxyInstance方法(具體作用等下說)返回了一個代理實例

ProImp proImp = new ProImp();//創建了實例類對象PorxyInte porxyInte =(PorxyInte) Proxy.newProxyInstance(ProImp.class.getClassLoader(), ProImp.class.getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("..."+proxy.getClass().getName());//輸出proxy對象的字節碼文件名Method[] declaredMethods = this.getClass().getDeclaredMethods();for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod.getName());}method.invoke(proImp,null);return null;}});System.out.println(porxyInte.getClass().getName());//輸出實現類的字節碼文件名porxyInte.test(); com.sun.proxy.$Proxy0 // 實現類的字節碼文件名 ...com.sun.proxy.$Proxy0// 參數proxy的字節碼文件名 在這邊我們發現我自己定義的實現類和參數proxy的字節碼文件名是一致的而根據前面對參數proxy的注釋定義,我們不難得出$Proxy0就是一個代理類那么為什么我調用了.newProxyInstance方法會生成一個代理對象呢?

newProxyInstance方法介紹

這是package java.lang.reflect.proxy下的一個靜態方法

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

我們需要注意的是它的三個參數

首先先介紹一下
第一個參數ClassLoader loader:類的加載器,傳入我們自定義類的加載器

第二個參數Class<?>[] interfaces 注意很重要 這個參數是傳入一個接口數組

第三個參數 h:類型是InvocationHandler,傳入InvocationHandler接口的子類

在newProxyInstance方法中 所做的幾件事情

!!重頭戲來了

第一步:

Class<?> cl = getProxyClass0(loader, intfs);

調用了getProxyClass0方法, 該方法 需要傳入兩個參數 一個是類加載器,一個是接口數組
在方法getProxyClass0 中 會創建出一個類$Proxy0 ,并且創建出這個內部類的引用返回
我通過生出的內部類文件,反編譯出源碼可以看下:

public final class $Proxy0 extends Proxyimplements PorxyInte {private static Method m1;private static Method m3;private static Method m2;private static Method m0;// 看到這個構造方法, 調用了父類Proxy構造方法,將我們得invocationhandler實例傳值過去//那這個構造方法觸發的時機就是在 // proxy得代理方法中 return cons.newInstance(new Object[]{h}); 通過反射來執行代理類得構造方法,//從而將invocationhandler實例從代理類賦值到父類,//也就是為什么在下面test方法中在super.h 這個不會產生空指針得重要原因public $Proxy0(InvocationHandler invocationhandler){super(invocationhandler);}public final boolean equals(Object obj){try{return ((Boolean)super.h.invoke(this, m1, new Object[] {obj})).booleanValue();}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}}public final void test(){try{super.h.invoke(this, m3, null);return;}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}}public final String toString(){try{return (String)super.h.invoke(this, m2, null);}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}}public final int hashCode(){try{return ((Integer)super.h.invoke(this, m0, null)).intValue();}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}}static {try{m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {Class.forName("java.lang.Object")});m3 = Class.forName("cn.itcast.web.Test.PorxyInte").getMethod("test", new Class[0]);m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);}catch (NoSuchMethodException nosuchmethodexception){throw new NoSuchMethodError(nosuchmethodexception.getMessage());}catch (ClassNotFoundException classnotfoundexception){throw new NoClassDefFoundError(classnotfoundexception.getMessage());}} } 注意:我們可以發現這個生成的類繼承了proxy 并且實現了我自己定義的那個接口 這是因為在調用getProxyClass0 傳入的接口數組,他會將這個數組遍歷,并且實現這是他實現的test方法: public final void test(){try{super.h.invoke(this, m3, null);return;}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}} super不難理解 是proxy類對象h :但是h是什么我相信小伙伴們可能有點懵,這里留下個懸念,我們先把newProxyInstance方法聊完剛剛說過newProxyInstance第一步返回了$proxy引用對象第二步: //通過反射創建出構造器對象,并且傳入constructorParams 類型參數private static final Class<?>[] constructorParams ={ InvocationHandler.class };final Constructor<?> cons = cl.getConstructor(constructorParams);//這是$proxy0的構造方法內部通過super(constructorParams) 創建父類對象//細心的小伙伴可能發現了,我們剛剛在$proxy中的h,在Proxy中進行了賦值//其實這個h就是我們在調用newProxyInstance方法是傳進來的第三個參數final InvocationHandler ih = h; 最后一步: return cons.newInstance(new Object[]{h}); 通過反射 返回$proxy的實例這個就是我們在掉用newProxyInstance方法所做的事情

那么先回到我們之前的疑問?invoke方法為什么會自動運行?

我相信現在小伙伴們也能理解
總體流程: 我在測試類中通過返回的$proxy引用調用test方法

porxyInte.test();

這時候會去調用$proxy方法中的test方法

public final void test(){try{super.h.invoke(this, m3, null);return;}catch (Error ) { }catch (Throwable throwable){throw new UndeclaredThrowableException(throwable);}}

在test方法中
super代表父類Proxy,h代表父類中的變量,也就是我們傳進來的InvocationHandler接口實例
然后又調用了實例中的invoke方法,這個時候是不是就一目了然,這就是為什么我們調用test方法,而 InvocationHandler中的invoke方法會自動運行的原因,這是因為在代理類中的test方法內容重新定義了

需要注意的點:
第一點:
很多剛接觸代理的小萌新包括博主我 在剛開始的時候都一直代理類當做是我們的自定義實現類對象
代理類不是我們定義的類,而是Proxy創建的$proxy類
第二點:
invoke方法中的第一個參數Proxy,這邊注意Proxy在invoke方法被賦值為this,this是誰呢?
他就是調用test方法的對象也就是我們的代理實例

return (String)super.h.invoke(this, m2, null);

到此為止,為什么動態代理invoke方法會自動運行的原因了
以上所有理解:都是博主自己的理解,如果有錯誤的地方,還請大家能一一指出,謝謝!!

總結

以上是生活随笔為你收集整理的jdk动态代理invoke方法自动运行原因的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。