JVM动态代理通过Proxy类在运行时生成代理字节码,调用ProxyGenerator.generateProxyClass生成$Proxy0类(继承Proxy、实现接口),所有方法委托InvocationHandler.invoke执行,并由ClassLoader加载到方法区或元空间。

JVM 动态代理本身不直接生成字节码,它依赖于 java.lang.reflect.Proxy 类在运行时自动生成代理类的字节码(基于接口),再通过内置的 ClassLoader 加载进内存。这个过程对开发者透明,但底层涉及字节码生成与类加载机制。
动态代理的字节码由 Proxy 类内部生成
Proxy.newProxyInstance() 调用时,JVM 会检查传入的接口列表,然后:
- 调用
ProxyGenerator.generateProxyClass()(该方法在sun.misc.ProxyGenerator中,非公开 API,但可反射调用)生成符合 JVM 规范的 class 字节码; - 生成的类名形如
$Proxy0,继承Proxy,实现所有传入的接口; - 每个接口方法都被重写为调用
InvocationHandler.invoke(),把原始调用委托出去。
生成的字节码由系统类加载器(或指定 ClassLoader)加载
Proxy 类内部使用 defineClass()(通过反射调用 ClassLoader.defineClass())将字节数组转为 Class 对象:
- 默认使用传入的
ClassLoader(通常是应用类加载器); - 该
ClassLoader调用本地方法defineClass1(),把字节码校验、解析、链接后注册到 JVM 方法区(Java 8 及以前)或元空间(Java 9+); - 之后即可通过
Class.newInstance()或反射构造器创建代理实例。
可以手动获取并查看生成的字节码(用于调试)
虽然 Proxy 不提供公开 API 导出字节码,但可通过以下方式捕获:
立即学习“Java免费学习笔记(深入)”;
- 设置系统属性:
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");(仅 JDK 8 及之前有效,JDK 9+ 已移除); - 使用 Java Agent + 字节码库(如 ByteBuddy、ASM)拦截
defineClass调用; - 反射调用
ProxyGenerator.generateProxyClass("MyProxy", interfaces)获取 byte[],再保存为 .class 文件用反编译工具查看(需注意 JDK 版本兼容性)。
注意:CGLIB 等第三方代理不是 JVM 原生机制
不同于 Proxy,CGLIB 使用 ASM 直接操作字节码,生成目标类的子类(而非仅接口),因此能代理没有接口的类。但它依赖外部库,且需要绕过 final 方法/类限制,和 JVM 动态代理是两条技术路径。


















