合理划分业务模块边界需以限界上下文为核心,封装完整闭环业务能力,通过module-info.java强制约束api暴露,确保模块可独立演进、替换与理解。

合理划分业务模块边界,关键在于让每个模块真正承载一个可独立理解、演进和交付的业务能力,而不是按技术分层或代码量机械切分。
以业务域为核心,不是按Controller/Service/DAO分包
把“用户”“订单”“支付”当作模块名只是起点,真正的模块应封装完整闭环业务逻辑:
- 用户中心模块:包含注册流程、手机号绑定、实名认证策略、风控校验,而不仅是User实体和UserMapper
- 订单履约模块:覆盖下单、库存预占、发货调度、物流对接、异常回滚,对外只暴露OrderService接口
- 营销引擎模块:管理优惠券生命周期、满减规则引擎、活动状态机,通过SPI或事件被其他模块调用
模块内部仍可自由分层,但跨模块调用必须走明确定义的API包,禁止直接引用对方的DAO实现类或DTO。
用“限界上下文”识别真实业务边界
和领域专家一起梳理业务语言,发现语义差异点——这就是天然的模块分界:
- “客户”在销售侧指潜在线索,在客服侧指已购用户 → 应拆为两个上下文,各自建模
- “库存”在商品页展示是快照值,在下单时是强一致性预占 → 属于不同上下文,数据模型与一致性要求都不同
- 一次事件风暴中浮现的聚合根(如Order、Payment、Shipment)往往就是模块的核心实体
每个限界上下文对应一个模块,拥有自己的通用语言、领域模型、数据存储边界,不共享数据库表或实体类。
用module-info.java固化边界约束
Java平台模块系统(JPMS)不是锦上添花,而是守住边界的强制手段:
- 在module-info.java中只exports API包(如com.example.order.api),其余包默认不可见
- 用uses声明SPI接口,用provides … with声明实现,解耦接口与具体实现
- 禁止跨模块import内部包——编译期报错比运行时报错更早暴露设计问题
模块不是命名空间,而是有门禁的“小王国”。exports什么,别人就能用什么;没exports的,连编译都过不去。
验证模块是否合理:三问法
划完模块后,快速自检:
- 这个模块能否由一个小型团队独立开发、测试、发布?
- 更换其实现(比如把MyBatis换成JOOQ,或把微信支付换成银联)是否不影响其他模块编译和运行?
- 新来同事只看该模块的API包和README,能否说清它解决什么业务问题、输入输出是什么?
三个问题中任一回答是否定的,说明边界还不够清晰,需要重新审视职责归属。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











