强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

微服务拆分精讲 / 第 03 章:领域驱动设计

第 03 章:领域驱动设计

DDD 不是技术,而是思维方式。它教我们用业务语言来设计系统,用限界上下文来划分边界。


3.1 DDD 核心概念

3.1.1 什么是领域驱动设计

领域驱动设计(Domain-Driven Design,DDD)是 Eric Evans 在 2003 年提出的一种软件设计方法论。它的核心思想是:

软件设计的核心复杂性在于业务领域,而非技术实现。

┌──────────────────────────────────────────────────────┐
│                   DDD 分层架构                        │
├──────────────────────────────────────────────────────┤
│                                                      │
│  ┌───────────────────────────────────────────────┐  │
│  │           用户接口层 (Interface Layer)          │  │
│  │    Controller · DTO · API Gateway              │  │
│  └──────────────────────┬────────────────────────┘  │
│                         ▼                            │
│  ┌───────────────────────────────────────────────┐  │
│  │           应用层 (Application Layer)            │  │
│  │    Application Service · 编排 · 事务管理        │  │
│  └──────────────────────┬────────────────────────┘  │
│                         ▼                            │
│  ┌───────────────────────────────────────────────┐  │
│  │           领域层 (Domain Layer) ⭐ 核心          │  │
│  │    Entity · Value Object · Aggregate           │  │
│  │    Domain Service · Domain Event               │  │
│  └──────────────────────┬────────────────────────┘  │
│                         ▼                            │
│  ┌───────────────────────────────────────────────┐  │
│  │          基础设施层 (Infrastructure Layer)       │  │
│  │    Repository · ORM · MQ · External API        │  │
│  └───────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────┘

3.1.2 DDD 战略设计 vs 战术设计

维度 战略设计(Strategic) 战术设计(Tactical)
关注点 业务边界划分 代码结构设计
核心概念 限界上下文、上下文映射 聚合、实体、值对象
参与者 架构师 + 业务专家 开发团队
输出物 上下文地图、服务划分方案 领域模型代码
与微服务的关系 指导服务拆分 指导服务内部设计

3.1.3 统一语言(Ubiquitous Language)

统一语言是 DDD 的基石——开发团队和业务专家使用同一套术语进行沟通。

  ❌ 开发人员和业务人员说不同的话

  开发:"我在 user 表加了一个 status 字段,0 表示未激活..."
  业务:"什么 status?我们叫'客户状态',有'新注册'、'已认证'、'已冻结'..."

  ✅ 统一语言:双方使用相同的术语

  术语表:
  ┌──────────────┬────────────────────────────┐
  │ 术语         │ 含义                        │
  ├──────────────┼────────────────────────────┤
  │ 客户 (Customer) │ 已完成注册并通过认证的用户  │
  │ 客户状态     │ 新注册 / 已认证 / 已冻结     │
  │ 订单 (Order) │ 客户发起的购买请求           │
  │ 订单项 (LineItem) │ 订单中的一个商品及数量   │
  └──────────────┴────────────────────────────┘

💡 实践建议:在项目开始时建立术语表(Glossary),并在整个团队中推广使用。代码中的类名、方法名应该直接使用统一语言中的术语。


3.2 限界上下文(Bounded Context)

3.2.1 概念

限界上下文是 DDD 中最重要的概念,也是微服务拆分的核心依据。

限界上下文是一个边界,在这个边界内,领域模型的每个术语都有明确且唯一的含义。

┌─────────────── 电商系统 ───────────────────────┐
│                                                │
│  ┌─────────────────┐  ┌─────────────────┐     │
│  │   销售上下文     │  │   物流上下文     │     │
│  │                 │  │                 │     │
│  │ "订单" = 购买   │  │ "订单" = 发货   │     │
│  │  请求,包含     │  │  指令,包含     │     │
│  │  商品、金额     │  │  地址、包裹     │     │
│  └─────────────────┘  └─────────────────┘     │
│                                                │
│  ┌─────────────────┐  ┌─────────────────┐     │
│  │   客户上下文     │  │   支付上下文     │     │
│  │                 │  │                 │     │
│  │ "客户" = 已注册  │  │ "客户" = 付款方 │     │
│  │  的用户,有     │  │  有账户余额     │     │
│  │  会员等级       │  │  和支付方式     │     │
│  └─────────────────┘  └─────────────────┘     │
└────────────────────────────────────────────────┘

同一个词 "订单"、"客户" 在不同上下文中含义不同!

3.2.2 识别限界上下文的方法

方法 操作步骤 输出
事件风暴(Event Storming) 组织工作坊,用便利贴梳理业务事件 领域事件序列
名词提取法 从业务文档中提取名词,分析聚类 实体/概念分组
业务流程分析 梳理核心业务流程,识别阶段边界 流程阶段划分
组织架构映射 参考部门/团队职责划分 组织-领域对应

3.2.3 事件风暴(Event Storming)实操

事件风暴是 Alberto Brandolini 发明的协作式建模方法:

  时间轴 ──────────────────────────────────────────▶

  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
  │ 🟡 命令  │    │ 🟡 命令  │    │ 🟡 命令  │    │ 🟡 命令  │
  │ 提交订单 │    │ 支付订单 │    │ 发货     │    │ 确认收货 │
  └────┬────┘    └────┬────┘    └────┬────┘    └────┬────┘
       ▼              ▼              ▼              ▼
  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
  │ 🟠 事件  │    │ 🟠 事件  │    │ 🟠 事件  │    │ 🟠 事件  │
  │ 订单已   │    │ 支付已   │    │ 订单已   │    │ 订单已   │
  │ 提交     │    │ 完成     │    │ 发货     │    │ 完成     │
  └────┬────┘    └────┬────┘    └────┬────┘    └────┬────┘
       ▼              ▼              ▼              ▼
  ┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
  │ 🔵 聚合  │    │ 🔵 聚合  │    │ 🔵 聚合  │    │ 🔵 聚合  │
  │  订单    │    │  支付    │    │  物流    │    │  订单    │
  └─────────┘    └─────────┘    └─────────┘    └─────────┘
       │              │              │
       ▼              ▼              ▼
  ┌─────────┐    ┌─────────┐    ┌─────────┐
  │ 🟣 上下文│    │ 🟣 上下文│    │ 🟣 上下文│
  │ 交易上下文│    │ 支付上下文│    │ 物流上下文│
  └─────────┘    └─────────┘    └─────────┘

操作步骤

  1. 召集工作坊:业务专家 + 开发团队(5-10 人)
  2. 梳理领域事件(橙色便利贴):用过去时描述,如"订单已提交"
  3. 识别命令(蓝色便利贴):触发事件的操作,如"提交订单"
  4. 标注聚合(黄色便利贴):处理命令的核心实体
  5. 划定边界(粉色线):将相关事件/聚合归入同一上下文

3.2.4 上下文映射(Context Mapping)

不同限界上下文之间的关系模式:

映射模式 英文 说明 示例
合作关系 Partnership 两个上下文紧密合作,共同演进 用户服务 ↔ 会员服务
共享内核 Shared Kernel 两个上下文共享部分模型 共享用户基础信息
客户-供应商 Customer-Supplier 上游提供,下游消费 商品服务(供)→ 订单服务(客)
防腐层 Anti-Corruption Layer 通过翻译层隔离外部模型 遗留系统接入层
开放主机服务 Open Host Service 提供标准化协议供多方使用 开放 API
遵从者 Conformist 下游完全遵从上游模型 使用第三方 SDK
各行其道 Separate Ways 两个上下文完全独立 推荐系统 ↔ 客服系统
┌──────────────┐    客户-供应商     ┌──────────────┐
│  商品上下文   │ ──────────────▶  │  订单上下文   │
│  (Supplier)   │                  │  (Customer)   │
└──────────────┘                  └──────┬───────┘
                                         │
                                    防腐层│(ACL)
                                         ▼
                                  ┌──────────────┐
                                  │  物流上下文    │
                                  │ (Legacy系统)  │
                                  └──────────────┘

3.3 聚合根(Aggregate Root)

3.3.1 概念

聚合(Aggregate)是一组相关对象的集合,作为数据变更的一致性边界。聚合根(Aggregate Root)是聚合的入口点,外部只能通过聚合根访问聚合内部的对象。

  ┌──────────────────────────────────────────────┐
  │              聚合:订单 (Order)                │
  │              聚合根:Order                     │
  │                                              │
  │   ┌──────────┐                               │
  │   │  Order   │ ◀── 外部只能通过 Order 访问     │
  │   │ (聚合根) │                               │
  │   └────┬─────┘                               │
  │        │                                     │
  │        ├──── OrderItem (实体)                 │
  │        │     ├─ productId                     │
  │        │     ├─ quantity                      │
  │        │     └─ price                        │
  │        │                                     │
  │        ├──── ShippingAddress (值对象)          │
  │        │     ├─ province                      │
  │        │     ├─ city                          │
  │        │     └─ detail                        │
  │        │                                     │
  │        └──── PaymentInfo (值对象)              │
  │              ├─ method                        │
  │              └─ transactionId                  │
  └──────────────────────────────────────────────┘

3.3.2 聚合设计原则

原则 说明 违反后果
聚合边界保护一致性 聚合内的事务必须强一致 数据不一致
通过 ID 引用其他聚合 聚合之间不直接持有对象引用 聚合边界模糊
一个事务只修改一个聚合 跨聚合操作通过领域事件 分布式事务难题
聚合根控制访问 外部不能直接修改聚合内部对象 一致性失控
小聚合优先 聚合尽量小,只包含必要元素 性能和并发问题

3.3.3 聚合设计实例

  ❌ 错误:聚合过大

  ┌──────────────────────────────────────────┐
  │  Order (聚合根)                           │
  │  ├─ OrderItems[]                         │
  │  ├─ Customer (整个客户对象) ← 不应该!    │
  │  │   ├─ name, email                      │
  │  │   ├─ addresses[]                      │
  │  │   ├─ paymentMethods[]                 │
  │  │   └─ membershipLevel                  │
  │  └─ Product (整个商品对象) ← 不应该!     │
  │      ├─ name, description                │
  │      ├─ images[]                         │
  │      └─ inventory                        │
  └──────────────────────────────────────────┘

  ✅ 正确:通过 ID 引用

  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
  │ Order       │     │ Customer    │     │ Product     │
  │ (聚合根)     │     │ (聚合根)     │     │ (聚合根)     │
  │             │     │             │     │             │
  │ customerId──┼──▶  │ id, name    │     │ id, name    │
  │             │     │ email       │     │ price       │
  │ items[]     │     │             │     │             │
  │ ├ productId─┼──▶  │             │     │             │
  │ ├ quantity  │     └─────────────┘     └─────────────┘
  │ └ price     │
  │ address     │
  └─────────────┘

3.4 领域事件(Domain Event)

3.4.1 概念

领域事件表示领域中发生的、业务专家关心的事情。它是聚合之间、限界上下文之间通信的主要方式。

  命令 (Command)          领域事件 (Domain Event)
  ─────────────           ────────────────────
  提交订单         ──▶     OrderSubmitted
  支付完成         ──▶     PaymentCompleted
  商品已发货       ──▶     OrderShipped
  库存不足         ──▶     StockInsufficient

3.4.2 领域事件命名规范

规范 ✅ 正确 ❌ 错误
使用过去时 OrderSubmitted SubmitOrder / OrderSubmit
业务语言 PaymentCompleted PaymentStatusChanged
具体而非笼统 OrderCancelled DataModified
不含技术术语 CustomerRegistered UserInsertedToDB

3.4.3 领域事件驱动的服务协作

  ┌──────────┐         ┌──────────┐         ┌──────────┐
  │ 订单服务  │         │ 支付服务  │         │ 库存服务  │
  │          │         │          │         │          │
  │ 创建订单  │         │          │         │          │
  │    │     │         │          │         │          │
  │    ▼     │         │          │         │          │
  │ 发布事件: │         │          │         │          │
  │ Order    │         │          │         │          │
  │ Submitted│         │          │         │          │
  └────┬─────┘         └──────────┘         └──────────┘
       │                                        │
       │          ┌──── 消息队列 ────┐           │
       ├─────────▶│ OrderSubmitted   │◀──────────┤
       │          └──────────────────┘           │
       │                │                        │
       │                ▼                        │
       │         ┌──────────┐                   │
       │         │ 支付服务  │                   │
       │         │ 创建支付  │                   │
       │         │ 记录      │                   │
       │         └────┬─────┘                   │
       │              │                         │
       │              ▼                         │
       │         发布事件:                       │
       │         Payment                        │
       │         Completed                      │
       │              │                         │
       │              ▼                         ▼
       │         ┌──────────┐          ┌──────────┐
       │         │ 订单服务  │          │ 库存服务  │
       │         │ 更新订单  │          │ 扣减库存  │
       │         │ 状态      │          │          │
       │         └──────────┘          └──────────┘

3.4.4 事件的结构

{
  "eventId": "evt-20260510-001",
  "eventType": "OrderSubmitted",
  "timestamp": "2026-05-10T10:30:00+08:00",
  "source": "order-service",
  "data": {
    "orderId": "ORD-20260510-001",
    "customerId": "CUST-001",
    "totalAmount": 299.00,
    "items": [
      {
        "productId": "PROD-001",
        "quantity": 2,
        "price": 149.50
      }
    ]
  },
  "metadata": {
    "correlationId": "req-abc-123",
    "version": "1.0"
  }
}

3.5 实体(Entity)与值对象(Value Object)

3.5.1 区别

维度 实体 (Entity) 值对象 (Value Object)
标识 有唯一 ID 没有 ID,通过属性值识别
可变性 可变 不可变
相等性 ID 相同即相等 所有属性相同才相等
生命周期 有独立生命周期 依附于实体
示例 Order, Customer, Product Money, Address, DateRange
  实体 (Entity)
  ┌────────────────────────┐
  │ Order                   │
  │ id: "ORD-001" ← 唯一标识 │
  │ status: PAID            │ ← 可变
  │ createdAt: 2026-05-10   │
  └────────────────────────┘

  值对象 (Value Object)
  ┌────────────────────────┐
  │ Money                   │
  │ amount: 100.00          │ ← 不可变
  │ currency: "CNY"         │
  │                         │
  │ Money(100, "CNY")       │
  │   == Money(100, "CNY")  │ ← 值相等即相等
  └────────────────────────┘

3.5.2 代码示例

// 实体 - 有唯一标识
public class Order {
    private String orderId;      // 唯一标识
    private OrderStatus status;
    private List<OrderItem> items;
    private Money totalAmount;   // 值对象

    public void cancel() {
        if (this.status == OrderStatus.SHIPPED) {
            throw new BusinessException("已发货订单不能取消");
        }
        this.status = OrderStatus.CANCELLED;
    }
}

// 值对象 - 不可变,无标识
public record Money(BigDecimal amount, String currency) {
    public Money add(Money other) {
        if (!this.currency.equals(other.currency)) {
            throw new IllegalArgumentException("币种不同不能相加");
        }
        return new Money(this.amount.add(other.amount), this.currency);
    }
}

3.6 从业务场景到服务划分

3.6.1 完整案例:外卖平台

第一步:事件风暴梳理业务流程

用户浏览餐厅 → 用户选择菜品 → 用户下单 → 餐厅接单 → 骑手取餐 → 骑手送达 → 用户评价

对应的领域事件:
CustomerBrowsed → ItemSelected → OrderPlaced → RestaurantAccepted
→ RiderAssigned → FoodPickedUp → FoodDelivered → OrderReviewed

第二步:识别限界上下文

上下文 包含的聚合 核心职责
用户上下文 Customer, Address 用户注册、认证、地址管理
餐厅上下文 Restaurant, Menu, Dish 餐厅入驻、菜单管理
订单上下文 Order, OrderItem 下单、订单状态管理
配送上下文 Rider, Delivery 骑手管理、配送调度
支付上下文 Payment, Refund 支付处理、退款
评价上下文 Review, Rating 用户评价

第三步:映射为微服务

┌──────────┐  ┌──────────┐  ┌──────────┐
│ 用户服务  │  │ 餐厅服务  │  │ 订单服务  │
│          │  │          │  │          │
│ Customer │  │ Restaurant│  │ Order    │
│ Address  │  │ Menu     │  │ OrderItem│
│          │  │ Dish     │  │          │
└──────────┘  └──────────┘  └──────────┘

┌──────────┐  ┌──────────┐  ┌──────────┐
│ 配送服务  │  │ 支付服务  │  │ 评价服务  │
│          │  │          │  │          │
│ Rider    │  │ Payment  │  │ Review   │
│ Delivery │  │ Refund   │  │ Rating   │
└──────────┘  └──────────┘  └──────────┘

3.6.2 上下文协作流程

  用户下单的完整流程:

  用户服务        订单服务        支付服务        餐厅服务        配送服务
     │               │               │               │               │
     │  创建订单      │               │               │               │
     │──────────────▶│               │               │               │
     │               │               │               │               │
     │               │  创建支付      │               │               │
     │               │──────────────▶│               │               │
     │               │               │               │               │
     │               │  PaymentCompleted              │               │
     │               │◀──────────────│               │               │
     │               │               │               │               │
     │               │  OrderPaid     │               │               │
     │               │──────────────────────────────▶│               │
     │               │               │               │               │
     │               │               │  RestaurantAccepted            │
     │               │◀──────────────────────────────│               │
     │               │               │               │               │
     │               │  OrderReady    │               │               │
     │               │──────────────────────────────────────────────▶│
     │               │               │               │               │
     │               │               │               │  DeliveryDone │
     │               │◀──────────────────────────────────────────────│
     │               │               │               │               │
     │  OrderCompleted               │               │               │
     │◀──────────────│               │               │               │

3.7 DDD 工具与框架

语言/平台 框架 说明
Java Axon Framework CQRS + Event Sourcing 框架
Java Spring Modulith 模块化单体 + DDD
.NET eShopOnContainers 微服务参考实现
Go go-ddd-skeleton DDD 项目骨架
Python eventsourcing 事件溯源库

⚠️ 注意事项

  1. DDD 不是万能的——简单 CRUD 业务不需要 DDD
  2. 限界上下文 ≠ 微服务——一个限界上下文可以包含多个服务
  3. 不要跳过事件风暴——直接画技术架构图会遗漏业务细节
  4. 聚合设计要谨慎——聚合过大导致性能问题,过小导致分布式事务
  5. 统一语言要落地——代码中的命名必须与统一语言一致

📖 扩展阅读

  1. Eric Evans - Domain-Driven Design: Tackling Complexity in the Heart of Software — DDD 圣经
  2. Vaughn Vernon - Implementing Domain-Driven Design — DDD 实践指南
  3. Alberto Brandolini - Introducing EventStorming — 事件风暴方法论
  4. Martin Fowler - BoundedContext — 限界上下文详解
  5. Chris Richardson - Microservices Patterns, Chapter 4 — DDD 与微服务结合

本章小结

要点 说明
DDD 核心 以业务领域为中心设计软件
限界上下文 微服务拆分的核心依据
聚合根 数据一致性的边界
领域事件 服务间通信的推荐方式
事件风暴 识别上下文的协作式方法

📌 下一章第 04 章:拆分策略 — 将 DDD 理论落地为可操作的拆分策略。