Contents
概述:理解 Fastjson 与 Java 模块系统 (JPMS) 的冲突
在将基于 Java 的 AI 服务(如使用 Spring Boot 部署的模型 API)迁移到 Java 9 及更高版本(尤其是 Java 17/21 LTS)时,开发者经常会遇到一个与 Fastjson 相关的反序列化错误:
1 com.alibaba.fastjson.JSONException: Unable to make private java.lang.Void() accessible: module java.base does not "opens java.lang" to unnamed module @5ba23b66
这个错误并非 Fastjson 独有,Jackson 或其他依赖反射机制的库在现代 Java 环境下也可能遇到。它标志着 Java 平台模块系统 (Java Platform Module System, JPMS) 带来的“强封装”特性在起作用,限制了外部库对 JDK 内部类的深层反射访问。
错误根源:强封装与反射
从 Java 9 开始,JDK 被划分为一系列模块。默认情况下,这些模块(包括 java.base)会对外部模块进行严格的封装。这意味着,即使是像 java.lang 这样的基础包,其内部的私有成员或构造函数也不能轻易被外部代码通过反射机制访问。除非该内部包被显式地“导出”(export)或“打开”(open)。
Fastjson 在反序列化某些复杂对象或泛型结构时,可能会尝试访问 java.lang.Void 的私有构造函数。由于 java.base 模块没有将 java.lang 包“打开”给应用模块(通常是“未命名模块”),JVM 就会抛出访问拒绝异常。
解决方案 1:升级 Fastjson(推荐做法)
最推荐和最干净的解决办法是升级序列化库。Fastjson 社区意识到了 JPMS 的问题,并进行了兼容性改进。
- Fastjson 1.x 用户: 确保版本在 1.2.68 或更高。这些版本通常包含了针对 JDK 9+ 兼容性的修复。
- 推荐迁移到 Fastjson 2.x: Fastjson 2.x 是对模块化环境的完全重写和优化,能更好地避免此类反射冲突。
Maven 升级示例 (Fastjson 2.x)
1
2
3
4
5 <dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.43</version>
</dependency>
解决方案 2:使用 JVM 参数强制开启访问权限
如果由于项目限制无法升级 Fastjson 或需要快速部署修复,可以通过在 JVM 启动时添加 –add-opens 参数,显式地告诉 JVM 允许特定的内部包被反射访问。这是最直接,也是在部署环境中常用的解决方案。
该参数的语法是:–add-opens
对于上述错误,我们需要打开 java.base 模块下的 java.lang 包,并允许所有未命名模块访问:
1 --add-opens java.base/java.lang=ALL-UNNAMED
部署脚本/命令行示例
如果你使用 java -jar 运行你的模型服务 Jar 包,你需要将参数放在 -jar 之前:
1 java --add-opens java.base/java.lang=ALL-UNNAMED -jar your-model-api.jar
Docker/Kubernetes 部署示例
在 Dockerfile 或 Kubernetes Deployment 中,修改 ENTRYPOINT 或 CMD 来包含这些参数:
1
2 # 示例 Dockerfile 片段
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-jar", "/app/app.jar"]
Spring Boot 配置示例
如果你是通过 Maven 或 Gradle 启动 Spring Boot 应用,可以在构建配置中加入参数。
Maven 示例 (Maven Failsafe Plugin for integration tests, or custom profile for running):
虽然对于生产环境通常在 shell 脚本中添加,但如果你需要开发环境的快速验证,可以通过 MAVEN_OPTS 或插件配置来设置:
1
2
3 # 在命令行设置 MAVEN_OPTS
export MAVEN_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED"
mvn spring-boot:run
总结与建议
这个 JSONException 是现代 Java 环境下的常见“陷阱”,它强调了在 Java 9+ 中维护 AI 基础设施时,对 JVM 运行时参数和依赖库兼容性的关注。虽然 –add-opens 能够快速解决问题,但从长期维护和安全角度考虑,推荐优先升级 Fastjson 到 2.x 版本,以彻底解决底层反射问题,避免在未来 Java 版本升级中遇到新的模块化冲突。
汤不热吧