必须用--add-opens java.base/包名=all-unnamed等jvm参数显式授权,格式严格为“源模块/包=目标模块”,需从异常堆栈提取模块名、包名及unnamed module信息,运行时生效且不可省略任一部分。

Java 9+ 的模块系统(JPMS)默认禁止跨模块反射访问,想让代码正常调用私有字段、方法或读取注解,必须在 JVM 启动时显式开放权限——核心手段就是 --add-opens 参数。
怎么写 --add-opens 参数
格式固定,不能颠倒或省略任何部分:
-
左边:模块名/包名,例如
java.base/java.lang或java.xml.bind/javax.xml.bind -
右边:接收方模块名,常见的是
ALL-UNNAMED(代表传统 classpath 下的代码,比如 Spring Boot jar、普通 main 方法) - 完整示例:
--add-opens java.base/java.util=ALL-UNNAMED
注意:ALL-UNNAMED 不是通配符,也不是“所有模块”,它特指未命名模块(即没写 module-info.java 的老式项目)。不要写成 =ALL-UNNAMED 放在左边,也不要用 * 替代包名。
怎么知道该开哪个模块和包
别猜,看报错堆栈:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 启动失败时抛
InaccessibleObjectException,错误信息里会明确写出被反射访问的类,比如java.util.ArrayList或java.lang.StackTraceElement - 查这个类属于哪个模块:基本类型、集合、时间、IO 等绝大多数都在
java.base;JAXB 在java.xml.bind(JDK 11+ 已移除,需额外引入);XML 解析可能涉及java.xml - 再提取它的包名,比如
ArrayList属于java.util,StackTraceElement属于java.lang
常见组合:
-
--add-opens java.base/java.lang=ALL-UNNAMED(String、Class、System、StackTraceElement) -
--add-opens java.base/java.util=ALL-UNNAMED(ArrayList、HashMap、ConcurrentHashMap) -
--add-opens java.base/java.time=ALL-UNNAMED(LocalDateTime、ZonedDateTime) -
--add-opens java.xml.bind/javax.xml.bind=ALL-UNNAMED(仅当使用 JAXB 且 JDK ≥ 11 时)
参数加在哪才生效
--add-opens 必须作为 JVM 参数传入,且要放在 -classpath 或 -jar 之前,否则会被忽略:
-
命令行启动:
java --add-opens java.base/java.lang=ALL-UNNAMED -jar app.jar - IDEA:Run → Edit Configurations → VM options 栏粘贴
-
Maven 测试:在
maven-surefire-plugin的<jvmargs></jvmargs>中配置 -
Docker:写进
ENTRYPOINT,如["java", "--add-opens=java.base/java.lang=ALL-UNNAMED", "-jar", "/app.jar"] -
Spring Boot fat jar:不能靠
java -jar传参(MANIFEST.MF 不支持),必须改用java -p ... -m模块方式,或通过spring-boot-maven-plugin配置jvmArguments
替代或补充方案
如果项目本身已模块化(有 module-info.java),优先在源码中声明,更规范、可维护:
- 在自己的模块中写:
opens com.example.entity to java.base;(让java.base的反射 API 能访问你这个包) - 若框架(如 Hibernate、Lombok)要反射你的类,就写:
opens com.example.model to org.hibernate.orm.core; - 注意:
exports不够,只有opens才支持运行时反射访问
另外,--illegal-access 参数已在 JDK 16 移除,不再可用;SecurityManager 在 JDK 17+ 被废弃,不建议依赖。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










