
动态代理原理
我们在上篇文章中提到通过调用Proxy类的newProxyInstance()方法生成了一个临时实例,这个实例就是我们需要的代理类。我们的代理类被动态的创建,省去了我们针对业务方法而手动实现如日志记录等功能。
我们继续深入,来详细看一下这个过程:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) {
...
//1. 获取传入的之前被代理类实现的接口
final Class<?>[] intfs = interfaces.clone();
...
//2. 生成设计好的代理类的Class对象
Class<?> cl = getProxyClass0(loader, intfs);
...
//3. 获取生成好代理类的带参构造方法,其中参数就是InvocationHandler接口的实例
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
//4. 通过构造方法生成代理类实例
return cons.newInstance(new Object[]{h});
...
}
这就是Proxy类newProxyInstance方法的核心逻辑,其中去除了一些判断和异常处理代码,这些都跟我们目前的讨论没有太大关系。
可以看出来,这里最重要的就是这一句:
//2. 生成设计好的代理类的Class对象
Class<?> cl = getProxyClass0(loader, intfs);
生成了设计好的临时代理类的Class对象之后,我们可以使用反射获取它的构造方法进而生成它的实例,这个Class对象的具体生成方法是什么呢?
我们继续探究它的实现方式:
/**
* 生成代理类的Class对象
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
...
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//使用缓存获取之前生成的Class对象,如果之前未生成,则使用ProxyClassFactory生成
return proxyClassCache.get(loader, interfaces);
}
这里使用到了缓存技术,如果之前生成过该类的Class对象,直接通过缓存返回它。我们这是第一次生成,看注释中提到:
If the proxy class defined by the given loader implementing
the given interfaces exists, this will simply return the cached copy;
otherwise, it will create the proxy class via the ProxyClassFactory
意思是之前已经创建过这个代理类,那么直接使用缓存,未建立的话使用ProxyClassFactory类建立代理类,通过缓存类的代码,我们发现其中调用了ProxyClassFactory的apply方法。我们现在做的就是研究代理类的生成机理,所以来看看ProxyClassFactory。
我使用的是eclipse,使用快捷键:Ctrl+Shift+T打开搜索界面,输入ProxyClassFactory,找到这个类。这个类其实是Proxy类 的一个内部类,我们通过eclipse发现其中只有一个方法apply,看来就是它了,它的代码是:
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
...
//1. 生成指定的代理类的二进制数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
...
//2. 通过生成的二进制数组proxyClassFile生成一个Class<?>类型的实例,这是一个native方法
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
和之前一样,略去了一些判断语句和生成细节等代码。
我们发现直接通过ProxyGenerator类的generateProxyClass方法得到了一个二进制文件,这个也就是我们平时说的.class文件。到此处已经比较清楚代理类的生成过程了,之后二进制文件的具体生成步骤不再跟进,有兴趣的读者可以继续深入研究。
最后根据这个.class文件通过虚拟机加载,解析,初始化生成代理类的Class类对象,最终,使用反射获取其构造方法后生成代理类的对象。
我们通过下面的图看可能会清晰一点:

其实用户接触的只有一个newProxyInstance方法,其余的方法都是层层调用被使用的。其实就具体就干了两件事:生成代理类Class对象和生成代理类对象,后者依赖于前者。
按照图中标注的顺序而且根据方法具体的行为来说:
a. 外部测试代码调用Proxy类的newProxyInstance方法
b. newProxyInstance方法中调用了Proxy类的getProxyClass0方法
c. getProxyClass0方法中调用Proxy类的内部类ProxyClassFactory类的apply方法
d. ProxyClassFactory类的apply方法中调用ProxyGenerator类的generateProxyClass方法,这步生成了一个二进制数组
e. generateProxyClass方法把二进制数组返回给apply方法
f. 之后apply方法继续调用native方法defineClass0,然后生成了一个Class类对象
g. Class对象返回给apply方法
h. Class对象返回给getProxyClass0方法
i. Class对象返回给newProxyInstance方法
j. newProxyInstance方法中使用返回的Class对象,通过反射获取其带参构造方法,之后生成一个代理类的对象,返回给测试类
具体行为对应的方法:
参考文章
[1] Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
[2] Java之美[从菜鸟到高手演练]之JDK动态代理的实现及原理)
[3] JAVA 动态代理