關於動態代理invoke()方法的理解


轉自:https://www.jianshu.com/p/774c65290218

1. 關於動態代理的一些疑問

學習動態代理時,總是會有疑問,使用代理對象調用我們自己的接口中的方法時,會執行InvocationHandler實現類的invoke()方法,並且返回值與接口的實現類的返回值沒有必然關系等等,出現了很多很奇怪的事情。
接口代碼:

public interface Dao { public void show (); public Object show2(); } class DaoImpl implements Dao { @Override public void show() { System.out.println("我是show()"); } @Override public Object show2() { System.out.println("我是show2()"); return "111"; } } 

動態代理代碼:

public class Demo { @Test public void show() { Dao dao = new DaoImpl(); InvocationHandler h = new DaoHandler(dao); Class[] interfaces = { Dao.class }; Dao d = (Dao) Proxy.newProxyInstance(this.getClass().getClassLoader(), interfaces, h); System.out.println(d.show2()); } } class DaoHandler implements InvocationHandler { Dao dao = null; public DaoHandler(Dao dao) { super(); this.dao = dao; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理開始"); Object result = method.invoke(dao); System.out.println("代理結束"); return null; } } 

代理對象調用show()方法


 
show方法.png

代理對象調用show2()方法


 
show2方法.png

實在忍耐不住好奇心,自己看了看源碼並且再結合百度的分析,大致理解了以下幾點

2. 個人的一些理解

  1. Proxy.newProxyInstance(//參數省略了...)的部分源碼
//Proxy類開始有這樣的一個定義 private final static Class[] constructorParams = { InvocationHandler.class }; protected InvocationHandler h; protected Proxy(InvocationHandler h) { this.h = h; } public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // Proxy類的方法getProxyClass,特別長....根據傳入的接口的Class對象與類加載器創建$proxy0類 Class cl = getProxyClass(loader, interfaces); // 通過反射帶參數構造傳入h實例化$proxy0,$proxy0類的帶參構造內部為super(h),其實就是給Proxy的成員h賦值,並返回此對象 Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } 
  1. 程序運行時產生一個類$proxy0
  2. $proxy0類繼承自Proxy類,實現了目標對象的父類接口(借鑒的百度提供的源碼)
  3. $proxy0類有多個Method成員變量,它的靜態代碼塊給Method賦值為我們自己的接口的實現類的對應的Method對象
  4. $proxy0實現接口的方法調用了super.h.invoke(參數),這里的參數包括Method變量
//$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("接口的實現類的路徑").getMethod("實現類的方法", 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 接口的實現類的方法() { 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 調用了對應的方法---此方法內部調用其父類的成員h調用h的invoke方法---就是調用傳入了InvocationHandler的invoke方法,至於返回值,那就看我們的InvocationHandler的實現類怎么寫了。

3. 動態代理之代理工廠實現

package cn.icast_03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory { private Object obj;//目標對象 private BeforeAdvice before; private AfterAdvice after; public Object newProxyInstance() { Object object = Proxy.newProxyInstance( this.getClass().getClassLoader(), obj.getClass() .getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (before != null) { before.before(); } //result即為接口的真實實現類的返回值 Object result = method.invoke(obj, args); if (after != null) { after.after(); } return result; } }); //object即為代理對象 return object; } public ProxyFactory() { super(); // TODO Auto-generated constructor stub } public ProxyFactory(Object obj, BeforeAdvice before, AfterAdvice after) { super(); this.obj = obj; this.before = before; this.after = after; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public BeforeAdvice getBefore() { return before; } public void setBefore(BeforeAdvice before) { this.before = before; } public AfterAdvice getAfter() { return after; } public void setAfter(AfterAdvice after) { this.after = after; } } //前置增強 interface BeforeAdvice { public void before(); } //后置增強 interface AfterAdvice { public void after(); } 

此工廠的前置增強與后置增強均為接口,在invoke內部,分別調用對應的方法。使用此工廠時,提供對應的目標對象,實現對應的增強接口(需要加入的代碼塊)即可。



作者:苑苑苑愛學習
鏈接:https://www.jianshu.com/p/774c65290218
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM