JDK动态代理源码分析

Posted java锦囊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK动态代理源码分析相关的知识,希望对你有一定的参考价值。

    上面对源码一顿分析,接下来我们将demo中调用bind方法中Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this)动态生成的代理类打印出来,修改我们的demo

package about_proxy.dynamic_proxy;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by solie_h on 2018/2/7.
 */

public class TestDynamicProxy {

    public static void main(String args[]){
//        Subject sub = new RealSubject();
        ProxyHandler proxy = new ProxyHandler();
        //绑定该类实现的所有接口
        Subject sub = (Subject) proxy.bind(new RealSubject());
        // 将动态生成的代理类打印出来
        // 这里需要修改为你需要输出的路径
        String path = "请修改路径/TestProxy.class";
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",RealSubject.class.getInterfaces());
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        sub.doSomething();

    }

}

将生成的TestProxy.class文件反编译

import about_proxy.dynamic_proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
  extends Proxy
  implements Subject
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
  
{
    try
    {
      return ((Boolean)h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void doSomething()
  
{
    try
    {
      h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
  
{
    try
    {
      return (String)h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
  
{
    try
    {
      return ((Integer)h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("about_proxy.dynamic_proxy.Subject").getMethod("doSomething"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]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

我们先来看该类的构造方法

 public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }

    传入参数为InvocationHandler,这就是为什么动态代理类在调用接口中方法时会走到自定义的InvocationHandler中的invoke方法。

    super(paramInvocationHandler),是调用父类Proxy的构造方法。而父类又持有protected InvocationHandler h的实例,参考Proxy的构造方法:

  protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

在继续看反编译出来文件的静态代码块

static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals"new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("about_proxy.dynamic_proxy.Subject").getMethod("doSomething"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]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }

我们在接口中定义的方法doSomething通过反射得到的名字是m3,我们继续查看文件中实现的

doSomething()方法

  public final void doSomething()
  
{
    try
    {
      h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

    这里调用代理对象的doSomething方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。 this.h.invoke(this, m3, null),其余的equals、toString、hashCode也是同样的道理。到这里就很明了了,所有的动态代理流程也清晰了。

JDK是动态生成代理类,并通过调用解析器,执行接口实现的方法的原理已经一目了然。动态代理加上反射,是很多框架的基础

以上是关于JDK动态代理源码分析的主要内容,如果未能解决你的问题,请参考以下文章

JDK动态代理[2]----JDK动态代理的底层实现之Proxy源码分析

JDK动态代理源码分析

JDK动态代理源码分析

设计模式3.2-- JDK动态代理源码分析有多香?

源码分析:Spring是如何跟JDK动态代理结合

源码分析:Spring是如何跟JDK动态代理结合