关于动态代理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