前言
Java中的动态代理是一个看起来很有有趣的技术,我们在一些开源项目中经常会见到动态代理的身影。本文就来看一下Java中动态代理到底是怎么实现的。
如何使用?
来看一下我写的demo:
/**
* blueberry
*/
public class DynamicProxyTest {
public interface TestInterface {
int add(int n1, int n2) throws Exception;
}
public interface TestInterface2 {
long multi(int n1, int n2, int n3) throws Exception;
}
static class Impl {
int add(int n1, int n2) throws Exception {
return n1 + n2;
}
long multi(int n1, int n2, int n3) throws Exception {
return n1 * n2 * n3;
}
}
public static void main(String[] args) throws Exception {
final Impl impl = new Impl();
Object proxy = Proxy.newProxyInstance(TestInterface.class.getClassLoader(), new Class[]{TestInterface.class, TestInterface2.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 最终应用层的调用会被转发到这里,【method】调用层调用的方法,[args]是调用层传递的参数,【proxy】是生成的代理对象
if ("add".equals(method.getName())) {
return (Object) impl.add((int) args[0], (int) args[1]);
} else if ("multi".equals(method.getName())) {
return impl.multi((int) args[0], (int) args[1], (int) args[2]);
} else if ("equals".equals(method.getName())) {
return "invoke equals";
} else if ("toString".equals(method.getName())) {
return "toString";
} else if ("hashCode".equals(method.getName())) {
return 20;
}
return "Empty";
}
});
System.out.println("newProxyInstance return:" + proxy);
TestInterface testInterface = (TestInterface) proxy;
int addResult = testInterface.add(10, 20);
System.out.println("10+20=" + addResult);
TestInterface2 testInterface2 = (TestInterface2) proxy;
long result = testInterface2.multi(10, 20, 30);
System.out.println("10*20*30=" + result);
}
}
这个示例中我写了两个接口(TestInterface和TestInteface2),然后调用Proxy.newProxyInstance(classLoader,proxy要实现的接口class数组,invocationHandler)
生成了一个proxy,随后就可以直接调用proxy中的方法,由于Proxy.newProxyInstance()
返回给我的直接是Object类型,所以我们在调用的时候需要将他强转为我们需要的类型。其中第三个参数的类型为InvocationHandler
,这个对象是有调用层传入的,实际上我们调用代理proxy的方法,最终会执行InvocationHandler
中的invoke方法。
InvocationHandler的定义:
public interface InvocationHandler {
// 第一个参数为:proxy的引用
// 第二个参数为:调用程序调用的方法。(这个method实际上是我们传入的接口的method)
// 第三个参数为:调用程序传入的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
上面那段程序的输出结果为:
newProxyInstance return:toString
10+20=30
10*20*30=6000
Process finished with exit code 0
细心的同学可以发现,我们也输出了"newProxyInstance return:toString"这句话,说明proxy.toString()
方法返回值为 "toString",这是因为我们在InvocationHandler中判断方法名为"toString“的时候我们return "toString"
。就是这么神奇!这是为什么呢?稍后我们分析一下系统怎么给我们生成的proxy类就会知道答案。
源码分析
- 首先我们看一下
Proxy#newProxyInstance
这个方法在做什么事情
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 忽略 安全检查相关的代码....
// 生成Proxy class
Class<?> cl = getProxyClass0(loader, intfs);
try {
//.. 忽略安全相关的代码...
final Constructor<?> cons = cl.getConstructor(constructorParams);
//.. 忽略安全相关的代码...
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
// 忽略异常处理相关的代码
}
可以看到这个函数就分2步:
第一步:调用getProxyClass0(loader,ints)创建出 Proxy的class
第二步:使用proxy class的构造器创建出proxy对象,并通过构造函数传入了,我们设置的invocationHandler
所以我们主要分析一下 getProxyClass0
的逻辑,就能摸清楚它是怎么一回事了。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
在Proxy的中可以看到proxyClassCache的定义与赋值为:
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
可以看到它是一个WeakCache
的实例,这个类支持三种泛型为:K、P、 V
分别代表 key,parameters,value
。并需要通过构造函数传入2个工厂,第一个工厂用来根据key,和 parameters计算出一个subKey。第二个工厂用来根据key和paramters计算出一个value。这个WeakCache
中 key与value实际上是一个弱引用关系,但是subKey与value之间是一个强引用关系。
结合proxyClassCache的定义我们可以看出proxyClassCache
中的Key为ClassLoader
,paramter为调用程序传入的interfactes的class。value就是最终生成代理类的class 其中用来生成subKey的工厂类为KeyFactory
,用来生成value的工厂为ProxyClassFactory
好的,我们接着看一下KeyFactory
的实现以及ProxyClassFactory的实现。
KeyFactory`:
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
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);
}
}
}
private static final class Key1 extends WeakReference<Class<?>> {
private final int hash;
Key1(Class<?> intf) {
super(intf);
this.hash = intf.hashCode();
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
Class<?> intf;
return this == obj ||
obj != null &&
obj.getClass() == Key1.class &&
(intf = get()) != null &&
intf == ((Key1) obj).get();
}
}
/*
* a key used for proxy class with 2 implemented interfaces
*/
private static final class Key2 extends WeakReference<Class<?>> {
private final int hash;
private final WeakReference<Class<?>> ref2;
Key2(Class<?> intf1, Class<?> intf2) {
super(intf1);
hash = 31 * intf1.hashCode() + intf2.hashCode();
ref2 = new WeakReference<Class<?>>(intf2);
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
Class<?> intf1, intf2;
return this == obj ||
obj != null &&
obj.getClass() == Key2.class &&
(intf1 = get()) != null &&
intf1 == ((Key2) obj).get() &&
(intf2 = ref2.get()) != null &&
intf2 == ((Key2) obj).ref2.get();
}
}
因为WeakCache
中subKey与value之间的对应关系是用ConcurrentHashMap
保存的,并且Key1,Key2,KeyX实现了hashcode,hashcode的值是通过我们传入的interfactes class的hashcode计算出来的,所以其实就是用了我们传入的Interfactes的class的hashcode作为key,与proxy class作为value,使用HashMap缓存了下来。
最后我们来看一下ProxyClassFactory
的实现
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有proxyClass 的名称前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 验证一下classloader能够加载我们传入的interfactes的class
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 验证我们传入的class都是interfactes的class
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 验证我们传入的没有重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 定义proxy的包名
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// 如果这些接口不是public的那proxy的报名就必须和接口们拥有同一个包名
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
// 如果接口都是public那么他的报名默认为:`com.sun.proxy`
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
// proxy的名称
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 核心:生成proxy class 的字节码数据
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 这个方式是Jni方法,我猜测加载这个class相关的代码,将class字节码数据转为Class<*>
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
所以我们分析一下 ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
这个方法返回的数据,就能看出来生成的proxy 的class结构了。
我写了如下程序dump出class数据:
public static void main(String[] args) {
byte[] bytes = ProxyGenerator.generateProxyClass("Proxy1", new Class[]{TestInterface.class,TestInterface2.class});
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(new File(".", "Proxy1.class"));
fileOutputStream.write(bytes);
fileOutputStream.flush();
fileOutputStream.getFD().sync();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != fileOutputStream) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
最终生成了一个Proxy1.class
文件,这里我们可以选择使用IntellijIDEA或者反编译工具查看它长啥样?
我用IntelligeIDEA打开Proxy1.class文件:
import com.example.retrofit.DynamicProxyTest.TestInterface;
import com.example.retrofit.DynamicProxyTest.TestInterface2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class Proxy1 extends Proxy implements TestInterface, TestInterface2 {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
private static Method m4;
public Proxy1(InvocationHandler var1) throws {
super(var1);
}
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 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);
}
}
public final int add(int var1, int var2) throws Exception {
try {
return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
} catch (Exception | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
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 long multi(int var1, int var2, int var3) throws Exception {
try {
return (Long)super.h.invoke(this, m4, new Object[]{var1, var2, var3});
} catch (Exception | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.retrofit.DynamicProxyTest$TestInterface").getMethod("add", Integer.TYPE, Integer.TYPE);
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m4 = Class.forName("com.example.retrofit.DynamicProxyTest$TestInterface2").getMethod("multi", Integer.TYPE, Integer.TYPE, Integer.TYPE);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到:1 、在它的静态方法区,它首先使用反射获取了我们用接口定义的那些方法,并且使用反射也获取了Object的equals
,toString
,hashCode
方法。
2、实现了我们定义的接口中的方法,以及equals
,toString
,hashCode
方法。并直接转发给了InvocationHandler
的invoke方法。这个InvocationHandler
实际就是我们调用Proxy.newProxyInstance(classLoader,interfaces,invocationHandler)
时传入的。
具体怎么传入的呢?
是因为生成Proxy class中的构造方法需要接受一个invacationhandler
在newProxyInstance
中
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
...
// 得到proxy class
Class<?> cl = getProxyClass0(loader, intfs);
....
// 构造函数传入invocationHandler
return cons.newInstance(new Object[]{h});
}
...
总结
最后我们来回顾一下这个流程。
- 首先调用程序通过
Proxy.newProxyInstance()
传入了3个参数classloader,interfaces的class,invocationHandler -
Proxy.newProxyInstance
的实现中首先使用getProxyClass0(loader,intfs)
获取proxy的class。然后使用反射proxyClass的构造函数,并传入invocationHandler的实例。创建proxy返回给调用层。
3.getProxyClasss0
的实现中,利用了WeakCache缓存了proxyClass。 - WeakCache中的
ProxyClassFactory
使用proxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
生成了proxy class - 最后我们自己写测试程序dump出了ProxyGenerator.generateProxyClass的结果,看看最终Proxy类的实现,分析出,它实际是将应用层的调用,转发给了InvocationHandler的invoke方法。