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动态代理源码分析的主要内容,如果未能解决你的问题,请参考以下文章