--add-exports仅能临时绕过模块限制使应用启动,不能替代代码改造;它不修复内部API硬依赖、掩盖真实风险、缺乏可移植性,且无法解决模块声明冲突。

不能替代,只能临时绕过。它解决的是“启动不报错”,不是“长期可维护”。
什么时候--add-exports看起来像能“代替改造”
常见于以下场景:
- 老项目升级到 JDK 11+ 后,因反射调用
sun.misc.Unsafe或jdk.internal.ref.Cleaner报IllegalAccessError - Lombok 编译失败,提示无法访问
com.sun.tools.javac.processing.JavacProcessingEnvironment - Spring Boot 应用集成旧版 Netty/Hibernate,启动时卡在模块访问检查
此时加一条 --add-exports java.base/jdk.internal.misc=ALL-UNNAMED 确实能让进程跑起来——但这只是把门锁撬开了,没换掉那把不安全的旧钥匙。
为什么它不能替代代码改造
原因很实际:
-
--add-exports不修复依赖关系:它不改变你代码对内部 API 的硬编码调用,JDK 版本一升级(比如 JDK 21 移除了jdk.internal.misc.Unsafe的某些字段),你的应用立刻崩溃 - 它掩盖真实风险:jdeps 工具扫不出你用了哪些内部类,但
--add-exports让你误以为“问题已解决”,结果上线后在信创环境(如毕昇 JDK 或龙芯 JDK)里因实现差异直接 fail-fast - 它不具备可移植性:同一参数在 JDK 17 上有效,在 JDK 21 上可能被默认拒绝(需额外配
--illegal-access=deny或改用--add-opens) - 它无法解决模块声明冲突:如果你的
module-info.java写了requires java.desktop;却没exports对应包,--add-exports也救不了跨模块的 public 类访问失败
真正该优先做的三件事
比堆 JVM 参数更关键的是:
- 用
jdeps --jdk-internals your-app.jar扫出所有对内部 API 的依赖,逐个替换为标准 API(例如用VarHandle替代Unsafe) - 检查第三方库版本:Lombok ≥ 1.18.30、Hibernate ≥ 6.0、Netty ≥ 4.1.100.Final 基本已适配模块化,旧版必须升
- 若必须保留内部调用(如某些信创中间件 SDK 强制依赖),应在
module-info.java中显式opens对应包,并配合--add-opens启动,而非盲目--add-exports
模块封装不是 bug,是设计。绕过它容易,但下次 JDK 升级时,那个被你跳过的 jdk.internal 包可能已经不存在了。











