直接在module-info.java中显式声明依赖可切断类路径隐式加载链,避免NoClassDefFoundError或IllegalAccessError;需精准requires真正调用的模块、最小化exports、用opens限定反射、将第三方库纳入模块路径,并启用--validate-modules和--illegal-access=deny等校验机制。

直接在 module-info.java 中显式声明依赖,能从根本上切断类路径(classpath)下隐式加载的变量依赖链,避免运行时因缺失、版本错配或反射越界引发的 NoClassDefFoundError 或 IllegalAccessError。
只导入真正用到的模块
每个 requires 语句都应对应代码中实际调用的 API。比如项目只用了 java.time.format.DateTimeFormatter,就只需 requires java.base;(自动包含),无需额外引入 java.sql 或 java.xml 等无关模块。
- 删掉未被任何 import 或反射调用引用的
requires行 - 避免使用
requires transitive暴露下游依赖,除非你明确要将该依赖“透传”给使用者 - 对第三方库,优先查其是否已模块化;若未模块化,JVM 会生成自动模块,名称通常来自 JAR 文件名(如
commons-lang3-3.14.0.jar→org.apache.commons.lang3),可在requires中按此名引用
导出范围最小化
仅 exports 被其他模块直接调用的公共 API 包,不导出工具类、内部配置或测试相关包。未导出的包在编译期即不可见,从源头杜绝非法访问。
- 例如:只
exports com.example.service;,不导出com.example.service.internal - 若需反射支持(如 JSON 序列化),用
opens替代exports,且限定目标模块:opens com.example.service.config to com.fasterxml.jackson.databind;
把第三方库纳入模块路径管理
隐式依赖常源于将第三方 JAR 放在 classpath 而非 modulepath,导致 JVM 无法识别其模块边界。必须确保所有依赖通过模块路径加载。
- Maven 项目需配置
<useModulePath>true</useModulePath>(Maven Compiler Plugin) - 命令行编译/运行时使用
--module-path(而非-cp)指定所有模块 JAR 和自动模块 - 构建自定义运行时镜像(
jlink)前,先用jdeps --list-deps检查真实依赖图,剔除未被引用的模块
用 javac 和 java 的模块检查能力提前拦截
启用模块系统自带的强校验,比等上线后报错更早发现问题。
- 编译时加
--module-source-path和--validate-modules,让 javac 报出循环依赖、未导出包被引用等问题 - 运行时加
--illegal-access=deny,禁止反射突破封装,强制暴露设计缺陷 - 配合
jmod list和jdeps -s定期审计模块间连接,识别“幽灵依赖”

















