JDK11中ProxyGenerator不再是public?

本文探讨在JDK11中遇到的ProxyGenerator类不再是public的问题,介绍了如何通过复制该类到自定义包下并调整方法权限,以实现动态代理生成字节码文件的需求。

我用的是JDK11,发现ProxyGenerator不再是public了

有时候需要JDK动态代理时生成的$Proxy0.class文件,而在高版本的JDK中,不知为什么这个类不在是public的,而是默认的class类型。一开始还有点懵,所以后来就把这个类拷贝到自己的包下了以及GetBooleanAction类,之后根据IDE的提示,把里面的方法加上@Override,当然不加也行.
如下图所示,之后就可以调用自己这个包下的类来生成字节码文件了。比如:byte[] proxyClassBytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
在这里插入图片描述

要查看 **JDK 动态代理生成的代理类源码**,可以通过以下方式实现: ## 一、JDK 动态代理类生成机制简介 当你调用 `Proxy.newProxyInstance()` 方法时,JVM 会在运行时动态生成一个代理类。这个类实现了你传入的所有接口,并将所有方法调用转发给 `InvocationHandler.invoke()`。 由于这些类是运行时生成的,不会写入磁盘文件中,因此需要手动配置 JVM 参数或使用工具将其保存下来。 --- ## 二、查看 JDK 动态代理类源码的方法 ### 方法1:通过 `sun.misc.ProxyGenerator` 手动生成并保存字节码 ```java import java.io.FileOutputStream; import java.lang.reflect.Proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import sun.misc.ProxyGenerator; public class ProxyClassGenerator { public static void main(String[] args) { // 创建目标对象 UserService userService = new UserServiceImpl(); // 获取 ClassLoader ClassLoader loader = userService.getClass().getClassLoader(); // 获取接口数组 Class<?>[] interfaces = userService.getClass().getInterfaces(); // 创建 InvocationHandler InvocationHandler handler = (proxy, method, args1) -> { System.out.println("前置处理"); Object result = method.invoke(userService, args1); System.out.println("后置处理"); return result; }; // 生成代理类实例(只是为了获取其 Class 对象) Object proxy = Proxy.newProxyInstance(loader, interfaces, handler); // 使用 ProxyGenerator 生成字节码 byte[] classFile = ProxyGenerator.generateProxyClass(proxy.getClass().getName(), interfaces); // 将字节码写入文件 try (FileOutputStream fos = new FileOutputStream(proxy.getClass().getName() + ".class")) { fos.write(classFile); System.out.println("代理类字节码已生成:" + proxy.getClass().getName() + ".class"); } catch (Exception e) { e.printStackTrace(); } } } // 接口和实现类 interface UserService { void addUser(String name); } class UserServiceImpl implements UserService { @Override public void addUser(String name) { System.out.println("添加用户: " + name); } } ``` #### 输出结果: - 生成一个类似 `com.sun.proxy.$Proxy0.class` 的字节码文件。 - 可以使用反编译工具(如 JD-GUI、IDEA 内置反编译)打开该 `.class` 文件查看代理类源码。 --- ### 方法2:设置 JVM 参数自动保存代理类(推荐) 在启动程序时加入如下 JVM 参数: ```bash -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true ``` 例如: ```bash java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true ProxyClassGenerator ``` > ✅ 注意:此参数适用于 JDK 8 及以下版本JDK 9+ 已经移除了 `sun.misc.ProxyGenerator` 的公开访问权限,可能无法直接使用。 --- ## 三、代理类结构示例(反编译后) ```java public final class $Proxy0 extends Proxy implements UserService { private static Method m1; private static Method m2; private static Method m3; public $Proxy0(InvocationHandler var1) { super(var1); } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("UserService").getMethod("addUser", Class.forName("java.lang.String")); } catch (Exception var2) { throw new Error(var2); } } public final void addUser(String var1) throws { super.h.invoke(this, m3, new Object[]{var1}); } public final boolean equals(Object var1) throws { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } public final String toString() throws { return (String)super.h.invoke(this, m2, null); } } ``` 可以看到,代理类继承自 `Proxy`,并实现了 `UserService` 接口,所有方法都委托给了 `InvocationHandler`。 --- ## 四、总结 | 方式 | 是否推荐 | 说明 | |------|----------|------| | `ProxyGenerator.generateProxyClass()` | ✅ 推荐 | 可控性强,适合调试 | | JVM 参数 `-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true` | ✅ 简单 | 适合快速查看 | | IDE 插件/反编译工具 | ✅ 辅助 | 如 IDEA、JD-GUI | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值