你想了解 Java 11 中 Proxy
动态代理的生成和执行原理,并结合底层源码进行详细说明。我会尽力为你剖析其核心机制。由于动态代理的底层源码涉及 Native 方法且代码非常复杂,我会重点阐述其核心流程和关键设计,并提供一些查看源码的建议。
⚙️ Proxy 动态代理的核心机制
Java 动态代理主要涉及 java.lang.reflect.Proxy
和 java.lang.reflect.InvocationHandler
。
Proxy
:提供静态方法(如newProxyInstance
)创建动态代理类和实例。InvocationHandler
:代理实例的方法调用会被分派到其调用处理器的invoke
方法。
🔧 代理类的生成过程
核心入口是 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
。
1. 获取或生成代理类 Class 对象
Proxy.getProxyClass0(loader, interfaces)
负责获取或生成代理类的 Class 对象。它使用了一个 WeakCache
(proxyClassCache
) 进行缓存,确保对同一组接口和类加载器,只会生成一个代理类。
// Proxy.java 片段
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
// ... 参数验证 (如接口数量上限检查)
return proxyClassCache.get(loader, interfaces); // 从缓存中获取或生成
}
如果缓存未命中,则会通过 ProxyClassFactory
(作为 WeakCache
的 ValueFactory
) 来生成代理类的字节码并定义类。
2. ProxyClassFactory 生成字节码
ProxyClassFactory.apply
方法是生成代理类的核心,其主要步骤包括:
- 验证接口:确保所有
interfaces
都是接口且非重复,类加载器能访问它们。 - 确定包名和访问权限:
- 如果所有接口都是
public
,代理类将在com.sun.proxy
包下。 - 如果存在非
public
接口,代理类将和该接口在同一包下。 - 代理类的修饰符通常是
public final
。
- 如果所有接口都是
- 生成代理类名:名称格式为
com.sun.proxy.$Proxy
+ 唯一数字(原子递增)。 - 生成字节码:调用
ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags)
生成代理类的字节码 (byte[]
)。ProxyGenerator
是sun.misc
包下的类,它会遍历所有接口的所有方法,生成对应的字节码。 - 定义代理类:调用
defineClass0
这个 Native 方法,将字节码数组 (byte[]
) 转换为Class<?>
对象。这个方法最终会调用ClassLoader
的defineClass
方法。
3. 生成代理实例
获取到代理类的 Class 对象后,newProxyInstance
方法会通过反射获取其参数类型为 InvocationHandler
的构造器:
// Proxy.java 片段
final Constructor<?> cons = cl.getConstructor(constructorParams); // constructorParams 为 new Class<?>[]{InvocationHandler.class}
然后,传入我们提供的 InvocationHandler
实例 h
,通过 cons.newInstance(new Object[]{h})
创建代理实例。这意味着生成的代理类都会有一个接收 InvocationHandler
参数的构造器。
📝 生成的代理类结构(概念模型)
通过设置系统属性 sun.misc.ProxyGenerator.saveGeneratedFiles
为 true
,可以将生成的代理类字节码文件(.class
)保存到磁盘,然后使用反编译工具查看。一个生成的代理类大致结构如下:
// 反编译后的 $ProxyN.class 概念模型
public final class $Proxy0 extends Proxy implements TargetInterface1, TargetInterface2 {
// 继承 Proxy 并实现你指定的接口
// 静态字段:缓存 Method 对象
private static Method m1; // hashCode()
private static Method m2; // equals()
private static Method m3; // toString()
private static Method m4; // 你的接口方法1
private static Method m5; // 你的接口方法2
// 静态初始化块:类加载时通过反射获取 Method 对象
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("hashCode");
m2 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("java.lang.Object").getMethod("toString");
m4 = Class.forName("com.yourpackage.TargetInterface1").getMethod("methodName1", ParameterTypes...);
m5 = Class.forName("com.yourpackage.TargetInterface2").getMethod("methodName2", ParameterTypes...);
// ... 其他方法
} catch (NoSuchMethodException | ClassNotFoundException e) {
throw new NoSuchMethodError(e.getMessage())