JDK 9 模块化后访问 JDK 内部集合类报错 IllegalAccessError 怎么解?

文章导读
遇到这类报错,最稳妥的办法是升级依赖库到支持新版 JDK 的版本,如果暂时无法升级,可以通过 JVM 启动参数临时开放模块访问权限,但这只是过渡方案。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 参考来源
A A

遇到这类报错,最稳妥的办法是升级依赖库到支持新版 JDK 的版本,如果暂时无法升级,可以通过 JVM 启动参数临时开放模块访问权限,但这只是过渡方案。

先说结论:这是 JDK 9 引入模块系统后的封装限制,优先升级依赖,其次才考虑用参数绕过。

  • 先确认:查看报错堆栈,确定是哪个模块和包被拦截
  • 先处理:添加`--add-opens` 参数或升级受影响的第三方库
  • 再验证:重启应用后观察日志,确认报错消失且功能正常

命令速用版

如果确定是内部 API 访问受限,可以在启动脚本中加入如下参数临时放行(以 java.base 为例):

java `--add-opens` java.base/java.util=ALL-UNNAMED -jar your-app.jar

注意:具体包名需要根据报错信息调整,不要直接复制所有示例。

JDK 9 模块化后访问 JDK 内部集合类报错 IllegalAccessError 怎么解?

为什么会这样

JDK 9 引入了模块系统(Project Jigsaw),目的是强封装内部 API。以前可以通过反射随意访问的 sun.* 或内部实现类,现在默认被禁止。这是为了提升安全性和维护性,防止外部代码依赖不稳定的内部实现。

分步处理

1. 定位受限模块:查看异常堆栈中的 error message,通常会提示 which module does not open the package to your module。记录涉及的模块名和包名。

2. 尝试升级依赖:检查报错涉及的第三方库(如 Lombok、Spring、Hibernate 等)是否有支持 JDK 11/17 的新版本。优先在 pom.xml 或 build.gradle 中升级版本。

JDK 9 模块化后访问 JDK 内部集合类报错 IllegalAccessError 怎么解?

3. 配置 JVM 参数:如果无法升级,在启动命令中添加`--add-opens` <module>/<package>=ALL-UNNAMED。例如报错提到 java.util.ArrayList 访问受限,可能需要开放 java.base/java.util。

4. 回滚准备:修改启动脚本前备份原文件,确保参数错误导致无法启动时能快速恢复。

怎么验证是否生效

应用启动后,观察控制台或日志文件,确认不再出现 IllegalAccessError 或 InaccessibleObjectException。同时执行涉及相关功能的核心业务流程,确保没有因反射失败导致的功能异常。

JDK 9 模块化后访问 JDK 内部集合类报错 IllegalAccessError 怎么解?

常见坑

1. 参数写错位置:`--add-opens` 必须放在 -jar 之前,否则会被当作应用参数传入而不是 JVM 参数。

2. 过度开放:不要为了方便直接开放所有模块,这会降低安全性且可能在后续 JDK 版本中彻底失效。

3. 忽略后续版本风险:JDK 17 及以后版本对内部 API 的限制更严格,临时参数可能在未来版本中被移除,长期必须修复代码或升级库。

参考来源

  • Oracle, "Migrating from JDK 8 to Later JDK Releases", https://docs.oracle.com/en/java/javase/11/migrate/migrating-jdk-8-later-jdk-releases.html
  • OpenJDK, "JEP 261: Module System", https://openjdk.org/jeps/261