Split Package错误本质是多个模块导出同一包名,违反JPMS唯一性约束;须确保每个包仅由一个模块导出,模块名须全局唯一、小写点分隔、符合反向域名规范,并与包结构协同设计。

Java 模块化系统中,模块命名冲突主要表现为“split package”(拆分包)错误或运行时 Module not found、cannot be accessed from module 等问题。根本原因不是名字“重复”,而是多个模块导出了**同一个包名**,或模块名本身不唯一、不规范,导致模块系统无法正确解析依赖关系。规范模块命名的核心是:**全局唯一 + 可读可维护 + 与包结构协同**。
模块名必须全局唯一且符合反向域名规范
模块名(module com.example.order; 中的 com.example.order)不是随意字符串,它在 JVM 模块图中是唯一标识符:
- 必须采用小写字母 + 点分隔,格式为 反向域名 + 业务路径(如
com.example.ecommerce.inventory),与组织域名强绑定,避免第三方冲突; - 禁止使用短横线、下划线、大写字母或数字开头(如
ecommerce-inventory、MyModule、123core均非法); - 模块名应反映其职责边界,例如
com.example.billing.api和com.example.billing.infra是两个独立模块,而非拼成一个长模块名。
模块名与包名需协同设计,杜绝 split package
“Split package” 是模块化中最常见也最致命的冲突——当两个不同模块都声明 exports com.example.shared.util;,JVM 就无法确定该包该由谁提供:
- 一个包(如
com.example.common.validation)只能由一个模块导出; - 若功能需复用,应将共享包提取为独立模块(如
com.example.shared),其他模块通过requires显式依赖它; - 模块源码根目录下的
module-info.java必须与该模块实际导出的包路径一致;例如模块名为com.example.payment,就不应导出com.example.user.dto。
模块命名要体现层级职责,避免模糊泛化
模块不是越短越好,也不是越长越安全,关键是让名字成为“职责说明书”:
立即学习“Java免费学习笔记(深入)”;
- 避免使用
common、util、core等宽泛词作为模块主干(如com.example.util),易引发范围不清和过度依赖; - 推荐按“领域+能力”组合,例如:
•com.example.auth.idp(身份提供商)
•com.example.auth.oauth2(OAuth2 协议实现)
•com.example.auth.jwt(JWT 工具封装) - 同一业务域下,模块名应保持语义连贯,便于团队理解边界,例如订单域统一以
com.example.order.*开头。
自动化校验与团队落地机制
再好的命名规则,脱离执行就是空谈:
- 在构建流程中接入 Checkstyle 或 Gradle Module Info Plugin,检查
module-info.java中模块名是否匹配正则^com\.[a-z]+(\.[a-z]+)*$; - 用 SonarQube 扫描“跨模块导出同名包”行为,提前拦截 split package;
- 新模块注册时,强制提交《模块边界说明书》,明确其导出包、依赖模块、SPI 使用情况,并由架构组评审通过后方可合并主干。


















