JPMS强制禁止多个模块导出同一包名,必须确保仅一个模块声明exports该包,其余模块通过requires依赖并移除重复类;需用jdeps扫描、--show-module-resolution验证,按职责或来源重构包名以彻底消除Split Package。

Java 模块化系统(JPMS)明确禁止多个模块导出同一包名,这不是可选的“规范建议”,而是强制的加载约束。一旦出现多个模块都声明 exports com.example.utils,编译或模块解析阶段就会直接失败,报 ResolutionException 或 error: package is declared in module 'xxx', which is not the current module。所以处理 Split Package 的核心不是“兼容它”,而是从设计源头切断它。
严格限定包导出权
一个包名只能由且仅由一个模块负责导出:
- 检查所有
module-info.java,确保只有唯一模块包含exports com.example.utils; - 其他模块若用到该包下的类,必须通过
requires显式依赖导出方,不可自行打包同名类或重复声明 exports - 若历史遗留导致两个模块都含
com/example/utils/Helper.class,需将其中一份移除,统一归口到主 utils 模块中
清理非模块化路径上的“幽灵类”
Split Package 常因旧式 classpath 混入造成——比如某个 jar 虽未声明 module-info.java,但内部仍含 com.example.utils 类,被 JVM 当作自动模块加载,与显式模块冲突:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 运行时加参数
--illegal-access=deny和--add-modules ALL-SYSTEM观察是否触发警告 - 用
jdeps --module-path mods/ --class-path lib/ MyApp.jar扫描依赖图,定位哪些 jar 包含重复包路径 - 把无模块声明但含业务包的 jar 改造成合格模块(补
module-info.java并重命名包),或彻底剔除
重构包结构打破语义重叠
当不同团队各自维护“utils”“common”等泛化包名时,物理隔离无法避免,必须靠语义区分:
立即学习“Java免费学习笔记(深入)”;
- 按职责细化:把
com.example.utils拆为com.example.validation、com.example.serialization等专属包 - 按来源标识:如
com.example.thirdparty.jackson、com.example.internal.cache,避免“utils”这类无信息量命名 - 若必须共用某工具类,应定义接口(如
IdGenerator)放于公共 API 模块,实现类放在各自模块中,通过服务发现加载
验证是否真正解决
不要只看编译通过,要确认运行时无歧义:
- 启动时加
--show-module-resolution,观察com.example.utils是否只被一个模块 resolve - 在关键类中打印:
System.out.println(Helper.class.getModule());,确认返回的是预期模块名 - 调试时查看变量类型全限定名,避免 IDE 缓存误导(如显示
Helper@123却来自错误模块)

















