Java实现动态代理,主要需要三个角色
1、被代理的接口以及代理接口的具体实现类
interface Interface { void sayHello(); void sayBye(); }
class InterfaceImpl implements Interface { @Override public void sayHello() { System.out.println("hello"); } @Override public void sayBye() { System.out.println("bye"); } }
2、用于处理具体代理逻辑的InvocationHandler
class ProxyInvocationHandler implements InvocationHandler { private Object instance; public ProxyInvocationHandler(Object instance) { this.instance = instance; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("start proxy for method " + method.getName()); method.invoke(instance, args); System.out.println("end proxy for method " + method.getName()); return null; } }
3、Proxy工厂类
Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler);
具体调用方法如下
public class ProxyDemo { public static void main(String[] args) { System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); InterfaceImpl target = new InterfaceImpl(); ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(target); Interface i = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, invocationHandler); i.sayHello(); i.sayBye(); } }
Java动态代理的实现方式是,根据Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)的前两个参数动态生成代理类,并InvocationHandler做为构造参数,传给生成的Proxy实例
可以通过配置System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");设置将生成的class类写入文件,代理类由sun.misc.ProxyGenerator生成
Proxy生成的代理类反编译后的代码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
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 Interface {
private static Method m3;
private static Method m1;
private static Method m4;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayBye() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m3 = Class.forName("Interface").getMethod("sayHello");
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("Interface").getMethod("sayBye");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m2 = Class.forName("java.lang.Object").getMethod("toString");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
Proxy在加载代理类时,使用了两层的缓存,一层是基于classloader的缓存,缓存了不同的classloader,而基于不同的classloader,会缓存已经生成的代理类,缓存的key基于newInstance方法中传入的interfaces而生成
生成Key的逻辑如下
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) { switch (interfaces.length) { case 1: return new Key1(interfaces[0]); // the most frequent case 2: return new Key2(interfaces[0], interfaces[1]); case 0: return key0; default: return new KeyX(interfaces); } }
而Key1,Key2,KeyX中则重写了对应的equals方法来区分是否相同
此外,如果在代理的接口中,存在内部接口,即不是申明为public的接口,那么Proxy生成的类的包名会是内部接口所处的包,如果实现的接口全部是public的,则会使用默认包名com.sun.proxy,同时生成的类名为Proxy+序列号,序列号由AtomicLong生成