领域驱动设计 (DDD) 架构完全解析

什么是 DDD (Domain-Driven Design)?

DDD 并不是一种框架(像 Spring Boot),也不是一种具体的技术(像 MySQL、ES),它是一种软件架构设计思想复杂业务系统的破局方法论

它的核心理念是:"软件设计的核心在于深刻理解和抽象真实的业务领域,让代码结构与现实业务逻辑保持高度一致。"

简单来说:以前我们写代码,是"面向数据库编程"(先建表,再写增删改查);而在 DDD 中,我们是"面向业务模型编程"(先理清业务概念,再考虑怎么存)。


为什么需要 DDD?(痛点与破局)

痛点:传统的"面条代码"与"大泥球"

在传统的 MVC 架构(Controller -> Service -> Dao -> 数据库表)中,当业务变得极其复杂时(比如全房通这种涉及租赁、财务、审批、维修的庞大系统):

  1. Service 层变得无限臃肿 :一个 HousingService.java 可能有几千行代码,里面塞满了业务校验、计算账单、发消息、调其他接口的逻辑。

  2. 贫血模型 (Anemic Domain Model) :我们写的 Housing 实体类(Entity)只有几十个 getset 方法,它本身没有任何业务逻辑。所有的逻辑都在 Service 里,实体成了一个单纯的"数据袋"。

  3. 牵一发而动全身:改了一个财务计算的 Bug,结果导致收房功能挂了。因为代码高度耦合。

DDD 的破局之道

DDD 将庞大的系统拆分成多个独立的**"界限上下文 (Bounded Context)"**,也就是微服务的雏形。比如:

  • 租赁域(管收房、出房、合同)

  • 财务域(管账单、流水、催收)

  • 基础域(管店面、员工、字典)

在每个域内,构建自己独立的充血模型(有状态、有行为的实体),各管各的事。


DDD 的四大核心概念 (以全房通系统为例)

1. 实体 (Entity) 与 值对象 (Value Object)

  • 实体 (Entity):有唯一标识,且状态会随时间变化的业务对象。

    • 例子qft_housing(房源)。一套房子从"未审核"变成"已租",它的状态在变,但它的房源编号(如 ZB0288)永远不变,它是实体。
  • 值对象 (Value Object):没有唯一标识,只用来描述事物特征的对象。

    • 例子:房子的"面积 (98㎡)"、"户型 (3室1厅)"。如果把 3室1厅 改成 2室1厅,它其实变成了一个全新的户型描述,这类属性通常作为值对象依附在实体上。

2. 聚合 (Aggregate) 与 聚合根 (Aggregate Root)

这是 DDD 最重要的概念。

  • 聚合:一组生命周期强绑定、需要保证数据一致性的实体和值对象的集合。

  • 聚合根:这个集合的"带头大哥"。外界想操作集合里的任何东西,都必须通过聚合根。

    • 例子qft_housing(房源)是聚合根qft_housing_cover_other_expenses(代扣附加费)是集合内的子实体。

    • 规则 :你不能跳过房源直接去给附加费表插一条数据;你必须调用房源聚合根的 addExpense() 方法,由房源自己去校验(比如:房源是不是被冻结了?)并最终落盘。

3. 领域服务 (Domain Service)

当一个业务逻辑跨越了多个聚合根,不适合放在任何一个单一的实体里时,就用领域服务。

  • 例子 :转租业务。涉及把 A 房源的租客退掉,并在 B 房源重新生成合同。这不属于 A 房源,也不属于 B 房源,这是一个跨聚合的 TransferHousingDomainService

4. 领域事件 (Domain Event)

当聚合根的状态发生重大改变时,向外发出的广播(通常借助 RabbitMQ / Kafka)。

  • 例子 :房源登记成功后,发出一个 HousingRegisteredEvent 事件。

  • 效果:财务域监听到这个事件,去生成账单;搜索域监听到,去更新 ES 索引。这就实现了模块间的彻底解耦。


DDD 典型的四层架构代码结构

如果全房通的后端严格按照 DDD 重构,它的代码目录大概长这样:

复制代码
com.qft.lease (租赁域)
├── api (用户接口层)
│   └── controller (接收 HTTP 请求,转交给应用层)
│
├── application (应用层)
│   └── service (负责编排调度,不写核心业务逻辑。如:开启事务 -> 调用领域模型 -> 发送 MQ 消息)
│
├── domain (领域层 - 核心!)
│   ├── model
│   │   ├── Housing (房源聚合根实体,里面写满了校验和状态流转的业务逻辑)
│   │   └── Expense (附加费实体)
│   ├── repository (只定义接口:HousingRepository,不写实现)
│   └── event (领域事件定义)
│
└── infrastructure (基础设施层)
    ├── persistence (这里才写 MyBatis/JPA,实现领域层的 Repository 接口,存入 MySQL)
    ├── mq (RabbitMQ 的发送实现)
    └── search (ES 的查询实现)

总结:DDD 带来的改变

  1. 代码即业务 :非技术人员看 Domain 层的代码(如 housing.checkOut()),就能看懂业务逻辑,不再是一堆干瘪的 setStatus(1)

  2. 保护核心资产 :无论外围的数据库从 MySQL 换成 Oracle,还是消息队列从 RabbitMQ 换成 Kafka(基础设施层变化),最核心的领域层(Domain)代码一行都不用改

  3. 完美契合微服务:按 DDD 的界限上下文拆分微服务,边界最清晰,不会出现服务间数据库乱连、逻辑乱调的"分布式大泥球"。

相关推荐
蝎子莱莱爱打怪6 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking7 天前
Java微服务练习方式
java·后端·微服务
米丘10 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质13 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
霸道流氓气质13 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
地瓜伯伯13 天前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
Devin~Y13 天前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
递归尽头是星辰13 天前
AI 访问数据仓库:从直连到微服务化
数据仓库·人工智能·微服务·dataagent·ai数据治理
就改了13 天前
Windows 环境 SkyWalking 完整实操教程
windows·微服务·skywalking
至乐活着14 天前
Docker Compose多服务编排实战:从零搭建Node.js+MySQL+Redis全栈应用
docker·微服务·devops·容器编排·compose