JDK 9+ 模块化下 Spring 反射访问私有字段需用 --add-opens 主动开放权限,如 --add-opens java.base/java.lang=ALL-UNNAMED,优先配置 java.base 下 lang/util/time/net 四个包,Maven/Gradle 可固化参数,避免非法语法和混淆 exports/opens。
Spring 等框架依赖反射访问私有字段(如
注入私有成员、
设置私有属性),但在 JDK 9+ 模块化系统下,这种访问默认被禁止,会抛出
。解决的关键不是绕过模块限制,而是用
主动、精准地开放所需包的反射权限。
明确哪些包需要 opens
常见报错指向三个核心模块:
:常需开放
、
、
、
等子包,因 Spring 反射操作
、
、
等内部结构
:若用到 AWT/Swing 相关类(较少见,但部分老工具类可能触发)
:仅当代码显式调用
等非标准 API 时才需开放(不推荐,应优先替换为标准替代方案)
在启动参数中配置 --add-opens
这是最直接有效的兼容方式。以 Spring Boot 应用为例,在运行命令中添加:
说明:
表示对
模块中的
包开放反射
表示向所有未命名模块(即传统 classpath 下的应用代码和第三方 jar)开放;若使用模块化应用,可指定具体模块名
多个
可并列使用,顺序无关
在构建工具中固化配置(避免手动传参)
Maven(pom.xml):
Gradle(build.gradle):
这样每次执行
或
都自动携带参数,开发阶段更省心。
验证是否生效与常见误区
启动后观察日志,若不再出现
,且 Bean 注入、配置绑定等功能正常,说明配置已起效。
注意避坑:
不要盲目加
—— 该语法非法,
不是合法模块名
不要混淆
和
:
解决编译期可见性,
才解决运行时反射访问
Spring Boot 3 + JDK 17 是主流组合,上述四个
已覆盖 95% 的注入场景;个别自定义类或第三方库触发新包时,按异常提示追加即可
@Autowired@ValueInaccessibleObjectException--add-opensjava.basejava.langjava.utiljava.timejava.netClassLoaderStringArrayListjava.desktopjdk.unsupportedsun.misc.Unsafe--add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.time=ALL-UNNAMED \
--add-opens java.base/java.net=ALL-UNNAMEDjava.base/java.langjava.basejava.langALL-UNNAMED--add-opens
org.springframework.boot
spring-boot-maven-plugin
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
bootRun {
jvmArgs = [
'--add-opens', 'java.base/java.lang=ALL-UNNAMED',
'--add-opens', 'java.base/java.util=ALL-UNNAMED'
]
}mvn spring-boot:run./gradlew bootRunInaccessibleObjectException--add-opens java.base/all-opens=ALL-UNNAMEDall-opens--add-exports--add-opensexportsopens--add-opens