全国咨询/投诉热线:400-618-4000

一文详解Proxy动态代理的内部机制

更新时间:2017年11月13日14时25分 来源:传智播客 浏览次数:

机制分析:其实JDK的动态代理,实际上就是“反射”与“执行时动态生成字节码”二者的结合体

$Proxy0=Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)做了以下2件事。

(1)根据参数loader和interfaces调用方法 Proxy的getProxyClass(loader, interfaces)创建代理类$Proxy0。

$Proxy0类实现了interfaces的接口,并继承了Proxy类。

(2)实例化$Proxy0并在构造方法中把InvocationHandler传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值

// Proxy类中有一个protected构造方法,接收一个InvocationHandler
class Proxy{
    InvocationHandler h=null;
    protected Proxy(InvocationHandler h) {
     this.h = h;
    }
    ...
 }
 // $Proxy0的部分代码如下所示
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.UndeclaredThrowableException;
 // IManager是代理实现的的接口,下面主要介绍了如何代理
 public final class $Proxy0 extends Proxy implements IManager {
 // 调用父类Proxy的构造方法传递InvocationHandler 
 public $Proxy0(InvocationHandler invocationhandler) {
    super(invocationhandler);
 }
 private static Method m1;
 private static Method m0;
 private static Method m3;
 private static Method m2;
 ....
 static {
    try {
     // 反射得到Object的方法对象(Method对象)
     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("com.ml.test.Manager").getMethod("modify",
       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());
    }
 }
 .......
 // 当调用代理类$proxy0的方法时,会回调$Proxy0=Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,    //  InvocationHandler h)中定义的InvocationHandler的Invoke()方法
 //          三个参数:this---代理类本身$Proxy0
 //          m1---相对应的Method对象
 //          new Object[]{}---方法的参数,没有参数传null
 @Override
 public final boolean equals(Object obj) {
    try {
    // 这句代码回调了你写的invoke()方法
     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 modify() {
    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的使用
 //  把得到的$Proxy0实例强制转换成IManager类型的managerProxy.
 IManager managerProxy = (Manager) Proxy.newProxyInstance(managerImpl
      .getClass().getClassLoader(), managerImpl.getClass()
      .getInterfaces(), invocationHandler);
 $Proxy0也实现了IManager接口中的所有方法,所以当调用managerProxy.modify(),就是执行下面这些代码
   try {
     super.h.invoke(this, m3, null);
     return;
    } catch (Error e) {
    } catch (Throwable throwable) {
     throw new UndeclaredThrowableException(throwable);
 }  

这样动态代理机制就实现了。

所以JAVA的动态代理的关键就在Proxy.newProxyInstance(..)方法执行时生成了$Proxy0的内存字节码以及JDK的反射机制!

本文版权归传智播客java学院所有,欢迎转载,转载请注明作者出处。谢谢!