刚在Java虚拟机书上看到了说Java的动态代理的实现机制,使我困惑很久的问题终于被解开,所以在这里记录一下.
先奉上测试代码(每个类或接口一个.java文件):
//等会儿会被代理的接口
//Java自带的动态代理生成的是代理接口的对象
public interface SayHello {
void sayHello();
}
//上面接口的一个实现类
public class HelloImpl implements SayHello {
public void sayHello() {
System.out.println("hello");
}
}
//会自动生成代理对象的动态代理类
public class DynamicProxy implements InvocationHandler {
//代理的是这个类的接口
Object originObj;
public DynamicProxy(Object originObj) {
this.originObj = originObj;
}
public Object getProxy() {
return Proxy.newProxyInstance(originObj.getClass().getClassLoader(), originObj.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("这句是代理打印的!");
return method.invoke(originObj, args);
}
}
//main方法
public class DynamicProxyTest {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//先生成一个原始实现了SayHello接口的实例,因为需要这个实例去生成代理实例
HelloImpl originHello = new HelloImpl();
//得到可以动态生成代理实例的对象
DynamicProxy proxy = new DynamicProxy(originHello);
//得到代理SayHello接口的实例对象
SayHello proxyHello = (SayHello) proxy.getProxy();
proxyHello.sayHello();
}
}
运行结果是:
这句是代理打印的!
hello
添加System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);这一条语句的作用是为了保存动态生成的代理类的字节码文件.
这里的黑匣子只有一句:
Proxy.newProxyInstance(originObj.getClass().getClassLoader(), originObj.getClass().getInterfaces(), this);
这条方法调用会在运行时生成一个代理类,代理SayHello接口的所有方法.
要看使如何做到得,必须查看自动生成的代理类的源码,这里用反编译工具jd-gui将生成的字节码文件反编译,得到的代码是:
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import top.geekgao.proxy.SayHello;
public final class $Proxy0
extends Proxy
implements SayHello
{
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)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
//主要看这里,这里是代理类的核心
public final void sayHello()
{
try
{
//this.h代表的就是Proxy.newProxyInstance()的最后一个参数,即上面main方法中的proxy对象
//有了h就可以调用它的invoke()方法
//m3代表的就是sayHello()方法,并且没有参数,所以是null
//这样就可以调用每一个方法了
this.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)this.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)this.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("top.geekgao.proxy.SayHello").getMethod("sayHello", 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());
}
}
}
书上说的是生成字节码文件是通过class文件规范去拼装,这个就先不理他了.