JDK11升级JDK17报jdk.proxy9未opens至未命名模块问题求助
项目从JDK11升级至JDK17时抛出访问权限错误:
无法使字段private static final java.lang.reflect.Method jdk.proxy9.$Proxy196.m0可被访问:模块jdk.proxy9未向未命名模块@18ad9d68 "opens jdk.proxy9"
最初尝试添加如下JVM参数修复,但配置完全不生效,运行后依然提示module jdk.proxy9 does not "opens jdk.proxy9" to unnamed module:
--add-exports java.base/sun.util.calendar=ALL-UNNAMED --add-opens java.base/sun.util.calendar=ALL-UNNAMED --add-exports java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED
之前添加的所有--add-opens/--add-exports规则都只针对java.base模块下的固定包,而本次报错涉及的jdk.proxy9是JDK运行时动态生成的代理类专属模块,不属于java.base范畴,原有规则根本没有命中报错的模块,自然不会生效。
方案1:临时添加匹配代理模块的启动参数(快速验证用)
在JVM启动参数中追加如下规则,开放动态代理模块的反射访问权限:
--add-opens jdk.proxy9/jdk.proxy9=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --illegal-access=permit
注意:jdk.proxy后的数字是运行时动态分配的,不是固定值,如果后续运行时代理类生成数量变化,数字可能变成10、11甚至更大,需要同步修改参数里的模块编号,否则会再次报错。这个方案仅适合临时跑通项目,不建议生产环境长期使用。
方案2:升级依赖适配JDK17(根治方案,推荐)
这类反射访问报错本质是项目引用的第三方依赖版本过低,没有适配JDK17的强模块封装规则,通过反射强行访问受限的内部类/字段导致的。把相关依赖升级到官方明确支持JDK17的版本,就不需要维护大量--add-opens参数,从根源解决问题。
常见需要升级的依赖包括:
- Spring/SpringBoot升级到2.7.x及以上版本,要使用JDK17新特性可以直接升级到3.x版本
- 字节码操作类库(ASM、ByteBuddy、Javassist、CGLIB)升级到支持JDK17的版本,Spring等框架内置的这类库跟着框架版本升级即可
- 测试组件(Mockito等)升级到适配JDK17的版本,旧版PowerMock对JDK17兼容性极差,建议替换为Mockito原生的静态Mock能力
内容的提问来源于stack exchange,提问作者Tablo_Jhin

