1. 文档目标
本文档基于项目脚手架说明整理,目的是统一团队对 DDD(领域驱动设计)开发模式的理解,并指导在当前工程中的实际落地方式,包括:
- 工程分层职责
- 目录结构设计
- 命名规范
- 接口规范
- 服务调用链路
- 微服务间调用方式
- 公共组件依赖原则
2. 为什么要采用DDD
传统三层架构通常按 Controller -> Service -> DAO 组织代码,虽然上手快,但随着业务复杂度上升,容易出现以下问题:
- 业务规则集中堆积在 Service 层
- 数据模型成为系统核心,业务语义表达不足
- 各层耦合较强,模型或规则变化时影响范围大
- 代码偏向"表结构驱动",不利于复杂业务演进
DDD 的核心目标,是让"领域模型"而不是"数据库结构"成为软件设计中心,把复杂业务规则沉淀到领域层,提升系统的可维护性、可扩展性和表达能力。
3. DDD四层架构
当前项目采用的是经典 DDD 四层架构,并结合适配器/防腐层思想进行工程化落地。
3.1 用户接口层(User Interface / Adapter / API)
职责:
- 对外暴露接口
- 接收请求、返回响应
- 完成参数转换
- 作为消息、事件等入口
特点:
- 不承载核心业务规则
- 只负责协议适配和调用应用层
- 是外部系统访问当前服务的入口
3.2 应用层(Application)
职责:
- 定义系统要完成的业务用例
- 编排领域对象完成业务流程
- 协调领域层与外部接口之间的调用关系
- 处理事务边界、输入输出 DTO、远程依赖抽象
特点:
- 应用层要"薄"
- 不应沉淀复杂业务规则
- 更关注"做什么",而不是"业务规则本身是什么"
3.3 领域层(Domain)
职责:
- 承载核心业务概念、业务规则和状态
- 表达领域模型
- 定义实体、值对象、领域服务、仓储接口、领域事件
特点:
- 是业务软件的核心
- 领域层不依赖其他业务层
- 业务变化优先体现在领域层
3.4 基础设施层(Infrastructure / Infra)
职责:
- 提供技术实现能力
- 实现仓储、远程调用、消息发送、配置、持久化、过滤器、异常等
- 实现领域层定义的接口
特点:
- 面向技术细节
- 通过依赖倒置为上层提供能力
- 隔离框架、中间件、数据库、远程服务等具体实现
4. 数据模型驱动与领域模型驱动对比
4.1 数据模型驱动
典型特点:
- 接口定义和实现集中在 API 层
- 业务逻辑集中在 Service 层
- DAO 和数据库模型成为核心依赖
- 表结构变化容易传导到服务层甚至接口层
问题:
- 业务语义弱
- 规则分散
- 演进成本高
4.2 领域模型驱动
典型特点:
- 接口能力仍由 API 层提供
- 业务逻辑拆分为"应用层编排 + 领域层规则"
- 领域层是业务核心
- 基础设施层通过依赖倒置实现技术隔离
优势:
- 业务规则归位
- 分层清晰
- 复杂业务更容易扩展和维护
5. 项目中的DDD工程结构
项目脚手架的核心结构可以理解为两个部分:
sdk:对外暴露接口契约biz:服务内部业务实现
5.1 SDK层
用于给其他服务依赖,主要包含北向接口定义:
adapter/api:对外 API 定义adapter/request:请求模型adapter/response:响应模型
作用:
- 统一服务间接口契约
- 便于微服务之间通过 jar 方式复用接口定义
5.2 Biz层
承载真正的业务实现,主要分为以下几层:
adapter
职责:
- API 实现
- 参数转换
- 消息/事件入口
常见子目录:
implconvertorlistener
application
职责:
- 定义应用服务
- 编排领域服务
- 定义输入输出 DTO
- 定义对外部服务依赖的抽象接口
常见子目录:
dto/inputdto/outputserviceservice/implremote
domain
职责:
- 承载业务核心模型
- 按领域划分子域
- 定义实体、领域服务、仓储接口、事件接口
常见子目录:
领域/entity领域/service领域/service/impl领域/repository领域/event
infra
职责:
- 实现技术能力与外部依赖
- 实现仓储、远程服务、事件发送等接口
- 提供异常、过滤器等基础能力
常见子目录:
adapter/api.impladapter/eventadapter/repositoryadapter/repository/convertoradapter/repository/mapperadapter/repository/poadapter/repository/implexceptionfilter
common
职责:
- 放置本服务公共能力
- 包括常量、枚举、工具类
常见子目录:
constantsenumsutils
6. 分层职责边界
为了避免职责混乱,开发时应遵守以下边界。
6.1 Adapter层应该做什么
可以做:
- 接收 HTTP / MQ / 事件请求
- 调用 Convertor 做对象转换
- 调用 Application Service
- 返回统一响应
不要做:
- 编写复杂业务规则
- 直接操作数据库
- 绕过应用层直接操作领域对象
6.2 Application层应该做什么
可以做:
- 编排业务流程
- 调用多个领域服务
- 控制事务边界
- 调用 remote 接口抽象
- 输出 DTO
不要做:
- 沉淀复杂领域规则
- 直接依赖数据库 Mapper
- 编写面向技术实现的细节代码
6.3 Domain层应该做什么
可以做:
- 表达实体状态和行为
- 编写领域规则
- 定义仓储接口
- 定义领域事件
- 实现领域服务
不要做:
- 依赖 Controller、Mapper、Feign、数据库表结构等技术细节
- 出现明显的接口协议对象,如 Request/Response/PO
6.4 Infra层应该做什么
可以做:
- 实现 Repository
- 实现 RemoteService
- 实现 EventPublisher
- 落地持久化、远程调用、消息发送
不要做:
- 反向主导业务规则
- 直接把 PO 当成领域实体使用
7. 推荐调用链路
7.1 Command操作
写操作推荐链路:
adapter -> application -> domain -> infra
说明:
- 接口层接收请求
- 应用层编排业务
- 领域层处理核心规则
- 基础设施层落地持久化或外部交互
7.2 Query操作
查询操作可采用以下方式:
adapter -> application -> domain -> infraadapter -> application -> infraadapter -> infra
其中:
- 普通查询建议优先使用第 2 种,降低复杂度
- 报表类、纯展示类查询可以使用第 3 种
- 如果查询包含明确业务规则,仍建议经过 domain
原则:
- 读操作可以适度简化
- 写操作尽量保持完整 DDD 链路
8. 微服务之间的调用方式
项目中推荐使用 OpenFeign 进行微服务调用。
8.1 服务提供方
- 将
interface-api模块打成独立 jar - 对外暴露 API、Request、Response 等契约模型
8.2 服务消费方
- 引入服务提供方的接口 jar
- 在
infrastructure层实现远程调用 - 通过
application.remote中定义的抽象进行依赖倒置
原则:
- 应用层依赖抽象
- 基础设施层依赖具体远程实现
- 避免应用层直接依赖 Feign 细节
9. 命名规范
9.1 类命名规范
interface-api:***Api、***Request、***Responseinterface/adapter:***Controller、***Convertorapplication:***AppService、***AppServiceImpl、***InputDto、***OutputDto、***RemoteService、***AppConvertordomain:***DomainService、***DomainServiceImpl、***Entity、***Repositoryinfrastructure:***RepositoryImpl、***RemoteServiceImpl、***Mapper、***Po、***InfraConvertor
9.2 包命名规范
统一格式:
com.gientech.ri.***.模块名
说明:
***为工程名简写- 启动模块可不追加模块名
10. REST接口设计规范
10.1 URL规范
统一格式:
/{系统名(可选)}/{应用名}/api/{业务模块(可选)}/{资源}(s)/{id}/{动作(可选)}?{param}={xxx}
10.2 HTTP动词规范
GET:查询POST:新增、复杂动作、批量处理PUT:更新DELETE:删除
10.3 非CRUD动作规范
对于批量操作、复杂业务动作,不使用模糊参数,而是在 URL 中显式表达动作,例如:
POST /arch-govern/api/govern/tasks/batch-updatePOST /arch-govern/api/govern/task/010/execute
这样做的好处:
- 语义清晰
- 单一职责明确
- 接口边界稳定
11. 公共组件依赖原则
项目中的公共组件遵循以下原则:
base和directory属于底层公共组件,不依赖其他三个公共组件base和directory之间可以相互依赖计划、项目、需求等公共组件,除依赖基础组件和目录组件外,最好不要相互依赖- 如果必须依赖其他服务,优先通过其
application层提供的服务进行调用
核心思想:
- 控制依赖方向
- 避免横向耦合
- 防止公共组件网状依赖
12. 开发落地建议
在当前脚手架下,推荐按以下顺序开发功能:
- 明确业务领域和子域边界
- 在
domain中定义实体、仓储接口、领域服务 - 在
application中定义用例、DTO 和编排逻辑 - 在
adapter中提供接口实现与对象转换 - 在
infra中补齐仓储实现、远程调用、消息实现 - 按命名规范和分层规范补充测试代码
13. 总结
本项目的 DDD 模式,本质上是在经典四层架构基础上,引入:
- 领域核心建模
- 应用层编排
- 基础设施隔离
- 适配器/防腐层思想
它强调的不是"目录拆分",而是"职责拆分":
- API层负责接入
- Application层负责编排
- Domain层负责业务规则
- Infra层负责技术实现
对于复杂业务系统,这种模式比传统三层架构更适合持续演进,也更有利于团队协作和代码治理。