模块化迁移中“重复定义module-info”本质是JVM在模块路径上发现同名模块或同一模块被多次加载,导致ResolutionException等错误;需检查多module-info文件、构建产物重复、Maven/Gradle配置冲突,并通过--list-modules、jar命令及依赖树排查。
模块化迁移中出现“重复定义 module-info”导致的变量解析错误,本质上不是 module-info.java 文件被写了两遍,而是 jvm 在模块路径(module path)上发现了多个同名模块,或同一模块被多次加载,从而引发模块系统拒绝解析、报错或类加载失败。
确认是否真有重复的 module-info
一个 Java 模块只能有一个 module-info.java,且必须位于模块根目录(即源码根路径下,与包结构同级)。检查以下常见误操作:
- 项目中存在多个
module-info.java,比如在src/main/java和src/test/java下各放了一个(测试模块应单独声明,如module-info.test不合法,需用test子模块或自动模块) - 构建产物(如
target/classes/module-info.class)被意外复制到另一个 JAR 或模块路径中,造成“同一个模块名出现两次” - Maven 多模块项目中,两个子模块使用了完全相同的
module name(例如都声明为module com.example.core),而未通过<classifier></classifier>或不同 artifactId 区分
排查模块路径上的冲突来源
JVM 启动时若在 --module-path 中遇到同名模块,会直接报错:java.lang.module.ResolutionException: Module xxx is defined in both A.jar and B.jar。解决方法包括:
- 运行命令查看实际加载的模块:
java --list-modules --module-path mods/,确认是否有重复模块名 - 用
jar -f your-module.jar | grep module-info检查 JAR 内是否含module-info.class - 检查构建输出目录(如 Maven 的
target/),删除残留的旧模块 JAR 或 classes 目录,避免历史产物干扰 - 若使用 IDE(如 IntelliJ 或 Eclipse),清理并重建项目,禁用“Add dependencies to modulepath automatically”等隐式行为
避免构建过程引入重复模块
Maven 和 Gradle 默认不强制模块唯一性,容易因依赖传递或配置疏漏埋下隐患:
- Maven:检查
<dependency></dependency>是否同时引入了同一库的命名模块版和传统 JAR 版(例如既依赖gson又依赖gson-module),JVM 会把后者当作自动模块,前者作为命名模块,但若两者导出相同包,仍可能触发冲突 - Gradle:确保
java { modularity.inferModulePath = true }不与手动module-info混用;禁用compileOnly引入的模块被错误打包进最终模块路径 - 使用
mvn dependency:tree -Dverbose定位重复引入的模块坐标,用<exclusions></exclusions>排除冗余项
修复已发生的解析错误
当错误表现为“找不到类”“无法访问包”或“Variable not resolved”,往往是因为模块未正确链接,而非字面意义的“变量重复定义”。此时应:
- 确认目标变量所在类所属的包已在
module-info.java中 exports(供其他模块读取)或 opens(供反射访问) - 检查调用方模块是否在
requires中声明了该模块,且模块名拼写完全一致(大小写敏感) - 若变量是
public static final常量,还需确保其所在类被exports,否则即使编译通过,运行时也无法解析符号引用 - 临时启用调试:启动参数加
--show-module-resolution,观察 JVM 模块解析全过程










