聚合目录落地骨架
新建聚合的第一步:照本文建立
{agg}的目录骨架,再按图索骥到各阶段落地模式文档填充。目录即地图——每个文件夹对应一篇(或多篇)模式文档。模块级四层全貌见 推荐项目结构。
1. 本质与定位
本文档把「新建聚合」的第一步模板化:初始化 domain/{agg} / application/{agg} / api/{agg} / controller/{agg} 目录骨架,并在基础设施层对应落地 persistent / dependency / config 下的 {agg} 目录。它不是单一能力点的模式,而是聚合全链路的目录地图——每个文件夹指向对应的落地模式文档,按目录逐个填充即完成聚合落地。
- 适用:在既有模块内新建聚合(如
order/product),或从零初始化一个模块。 - 不适用:理解框架整体分包与多模块拆分(见 推荐项目结构)。
2. 目录骨架(核心)
以四层分包为骨架;其中领域 / 应用 / UI 层以聚合 {agg} 为第一级,基础设施层以类型(persistent / dependency / config)为第一级、聚合为第二级:
text
{module}/
├── api/{agg}/ # UI:协议 Request / Response
│ ├── cmd/ # 命令协议
│ ├── query/ # 查询协议
│ └── dto/ # 响应 DTO
├── controller/{agg}/ # UI:{Agg}Controller
├── application/{agg}/ # Application:编排领域逻辑、汇聚依赖
│ ├── input/ # {Action}Input 业务语义入参
│ ├── factory/ # EntityFactory 聚合工厂(先算后赋)
│ ├── updater/ # EntityUpdater 修改场景编排
│ ├── resolver/ # Command → 领域输入适配
│ ├── rule/ # 规则容器组装
│ ├── service/ # 领域服务实现(@Service)
│ └── subscriber/ # 事件订阅登记
├── domain/{agg}/ # Domain:业务原子零件与契约(无 acl/ 包)
│ ├── model/ # 聚合根 / 实体 / 值对象(含 enums/ valueobject/)
│ ├── event/ # 领域事件
│ ├── operation/ # 操作注册表
│ ├── param/ # 参数对象 IParamObject
│ ├── rule/ # 规则容器 + 规则注册表
│ ├── service/ # 事件订阅 / 校验规则 / 能力供给契约
│ ├── calculator/ # 属性计算契约
│ ├── dependency/ # 外部依赖声明
│ ├── repository/ # 仓储抽象
│ ├── projection/ # 投影契约(含 replica/ 副本版本 / 补偿专属契约)
│ └── config/ # 领域配置
└── infrastructure/ # Infrastructure:技术实现,落地领域层契约(类型优先)
├── persistent/{agg}/ # 持久化:仓储实现 + 投影(projector/ searcher/ reducer/ + replica/ 写读一体源 / 版本 / 对账)
├── dependency/{agg}/ # 外部依赖实现(ACL 网关);跨聚合共享的放 dependency/shared/
└── config/ # @Configuration 装配(MySQL / ES / MQ / Outbox)
└── {agg}/ # 仅绑定聚合的配置进 config/{agg}/,通用配置放 config/ 外层⚠️ 分包维度:领域 / 应用层以聚合
{agg}为第一级(让单个聚合的契约与编排内聚成块),基础设施层以类型(persistent/dependency/config)为第一级、聚合为第二级(便于把通用技术配置与跨聚合共享适配器抽成单一来源,见 推荐项目结构 §2.3)。不同聚合不共享包或实体,聚合间通信走领域事件。
3. 按图索骥:目录 → 模式文档
建好目录后,按文件夹逐个填充,每个文件夹对应一篇(或多篇)落地模式:
| 目录 | 放什么 | 去查的模式文档 |
|---|---|---|
domain/{agg}/model | 聚合根、实体、值对象、枚举 | 聚合设计原则 · 普通实体设计原则 · 值对象最佳实践 · 枚举值对象最佳实践 |
domain/{agg}/event | 领域事件类 | 事件建模指南 |
domain/{agg}/operation | 操作注册表 | 操作注册表设计 |
domain/{agg}/param | 参数对象 | 聚合设计原则 §3.4 |
domain/{agg}/rule | 规则容器 + 规则注册表 | 规则注册表设计 · 聚合业务规则(OrderRule 范式) |
domain/{agg}/service + calculator | 四类领域服务契约 | 领域服务落地模式 |
domain/{agg}/dependency | 外部依赖声明 | 核心:依赖体系 |
domain/{agg}/repository | 仓储抽象 | 仓储设计原则 |
domain/{agg}/projection | 投影契约 | 投影读模型代码落地指南 |
application/{agg}/input | 业务语义入参 | 应用层落地模式 |
application/{agg}/factory + updater + resolver | 聚合装配 / 修改 / 适配 | 领域服务落地模式 · 应用层落地模式 |
application/{agg}/service | 领域服务实现 | 领域服务落地模式 |
application/{agg}/subscriber | 事件订阅登记 | 投影读模型代码落地指南 · RocketMQ 配置设计原则 |
infrastructure/persistent/{agg}/repository | 仓储实现 | 仓储设计原则 · MySQL 配置设计原则 |
infrastructure/persistent/{agg}/projection | 投影器 / 物化器 | 投影读模型代码落地指南 · Elasticsearch 配置设计原则 |
infrastructure/config(通用)+ config/{agg}/ | Bean 装配 | MySQL · Elasticsearch · RocketMQ · Outbox |
infrastructure/dependency/{agg}(+ shared/) | 外部依赖实现 | 核心:依赖体系 · ACL 防腐层 |
4. 四层职责速记
| 层 | 职责 | 不要放 |
|---|---|---|
| 领域层 Domain | 业务原子零件与契约 | SQL/ORM、RPC、MQ 发送、事务、Input |
| 应用服务层 Application | 编排领域逻辑、汇聚依赖 | 直接 new 基础设施实现、聚合根业务行为 |
| 基础设施层 Infrastructure | 技术实现,落地领域层契约 | 业务逻辑、领域规则、状态判定 |
| 用户接口层 UI | 协议适配与参数转换 | 业务编排、聚合调用、仓储直连 |
5. 关键机制与避坑
- 依赖方向:
UI → Application → Domain ← Infrastructure(基础设施实现领域层接口,依赖倒置)。 - 领域层零基础设施依赖:
domain/{agg}下不出现 Spring / MyBatis / MQ 导入;依赖外部能力用dependency声明 + 领域服务契约,由应用 / 基础设施层实现。 - 聚合间不共享:不同聚合目录独立,通信优先领域事件,不跨聚合直接 new 仓储 / 服务。
- 目录名即语义:
service只放领域服务契约(领域层)或实现(应用 / 基础设施层),不要混放业务逻辑类。
6. 常见反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
领域/应用层目录以技术分层为第一级(如 domain/repository/、application/service/) | 单个聚合的契约与编排散落各目录、难整体搬移 | 领域/应用层以聚合 {agg} 为第一级 |
基础设施层以聚合 {agg} 为第一级并在其下重复通用配置 | 通用数据源/适配器在每个聚合下各放一份、难复用 | 基础设施层类型优先:persistent / dependency / config 为一级、聚合为二级,通用放 config/、共享放 dependency/shared/ |
domain/{agg} 里出现 Spring / Mapper / MQ 导入 | 破坏领域层零基础设施依赖 | 依赖外部能力用契约 + 依赖声明 |
| 不同聚合共享包 / 实体 | 聚合边界模糊、事件驱动失效 | 聚合目录独立,通信走领域事件 |
service 包混放业务逻辑类 | 目录语义失真、难维护 | 契约 / 实现按层分离,业务逻辑内聚聚合根 |
| 跳过目录骨架直接写代码 | 结构散落、后续难以按模式填充 | 先初始化目录,再按图索骥填充 |