4. 限界上下文详解

限界上下文(Bounded Context)是领域驱动设计的核心战术模式,它划定了模型、术语和业务规则的明确边界。在 OpenAPI 规范中,每个限界上下文通常对应一组独立的 API 端点集合、Schema 定义和业务逻辑。理解限界上下文及其协作模式,是设计高内聚、低耦合 API 的关键。

4.1 限界上下文的定义与特征

限界上下文是一个显式的边界,领域模型在这个边界内部保持一致性,而边界外部的模型可以完全不同。每个限界上下文拥有自己的:

  • 通用语言(Ubiquitous Language):团队内部统一使用的术语和概念
  • 业务规则:独立的业务逻辑和约束条件
  • 数据模型:可能与其他上下文共享概念但结构不同
  • API 契约:对外暴露的接口定义
关键原则:两个限界上下文中的同名概念(如“订单”)可能具有完全不同的属性和行为。不要试图创建全局统一的“企业级数据模型”,这会导致耦合和僵化。
特征 说明 OpenAPI 映射
边界性 模型只在边界内有效 每个上下文对应独立的 API 规范文件或标签
一致性 内部模型无歧义 Schema 定义在上下文内唯一且完整
自治性 可独立演进和部署 API 版本、服务器地址独立管理
语言统一 团队使用相同术语 operationId、参数名、Schema 名称保持一致

4.2 上下文映射图

上下文映射图(Context Map)描述了不同限界上下文之间的协作关系。它帮助团队理解系统整体的集成方式,识别潜在的冲突点。常见的映射关系包括:

  • 合作关系(Partnership):两个上下文协同完成一个用例
  • 共享内核(Shared Kernel):共享部分模型但保持独立
  • 客户-供应商(Customer-Supplier):上游提供下游所需的数据
  • 防腐层(Anti-Corruption Layer):隔离外部模型的侵入
  • 开放主机服务(Open Host Service):通过 API 对外暴露能力
  • 发布语言(Published Language):使用标准格式交换数据
  • 分离方式(Separate Ways):完全独立,无集成
上下文映射图 — 典型电商系统 订单上下文 Order Service /api/orders 库存上下文 Inventory Service /api/inventory 支付上下文 Payment Service /api/payments 客户上下文 Customer Service /api/customers 物流上下文 Shipping Service /api/shipping 通知上下文 Notification /api/notifications 共享内核 (产品库存) 客户-供应商 (支付结果) 防腐层 (地址转换) 开放主机服务 (客户信息) 合作关系 图例说明 实线箭头 = 同步调用(REST API) 虚线箭头 = 异步/事件驱动(消息队列) 标签文字 = 上下文映射关系类型 每个方框 = 一个独立的限界上下文
实践建议:在 OpenAPI 设计中,使用 tags 字段标记每个端点所属的限界上下文。例如,所有订单相关的端点使用 tags: [Orders],便于在 API 文档中按上下文分组查看。

4.3 共享内核

共享内核(Shared Kernel)是指两个或多个限界上下文共享一部分领域模型。这些共享部分通常是高度稳定、变更频率极低的核心概念。共享内核需要团队间紧密协作,任何变更都需要多方评审。

4.3.1 共享内核的特征

  • 小规模:只共享真正必要的部分,避免“共享过多”导致耦合
  • 高稳定性:共享模型变更需要跨团队审批
  • 版本同步:所有使用共享内核的上下文必须同步升级
  • 测试共享:共享内核的测试用例对所有上下文可见

4.3.2 OpenAPI 中的共享内核实现

在 OpenAPI 规范中,共享内核可以通过 $ref 引用公共的 Schema 文件来实现:

# shared-kernel.yaml — 共享内核定义
components:
  schemas:
    Money:
      type: object
      properties:
        amount:
          type: number
          format: decimal
        currency:
          type: string
          pattern: '^[A-Z]{3}$'
      required: [amount, currency]

    Address:
      type: object
      properties:
        street:
          type: string
        city:
          type: string
        postalCode:
          type: string
        country:
          type: string
          pattern: '^[A-Z]{2}$'
      required: [street, city, country]

# order-service.yaml — 订单上下文引用共享内核
paths:
  /orders:
    post:
      tags: [Orders]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                items:
                  type: array
                  items:
                    $ref: './shared-kernel.yaml#/components/schemas/Money'
                shippingAddress:
                  $ref: './shared-kernel.yaml#/components/schemas/Address'
注意:共享内核的变更会传播到所有引用它的上下文。建议将共享内核的版本号独立管理,并在 OpenAPI 规范中使用 info.version 字段标注共享内核的版本。

4.4 防腐层

防腐层(Anti-Corruption Layer,ACL)是一种保护机制,防止外部系统的模型和概念“污染”当前限界上下文的纯净模型。当两个上下文使用不同的通用语言时,ACL 负责翻译和适配。

4.4.1 防腐层的职责

职责 说明 OpenAPI 实现方式
模型翻译 将外部模型转换为内部模型 在 API 网关或 BFF 层进行 Schema 转换
协议适配 将外部协议转为内部协议 使用 API 组合模式或适配器模式
验证与过滤 过滤无效或恶意数据 在 OpenAPI 的 requestBody 中定义严格的 Schema 验证
缓存与降级 应对外部系统不可用 在 API 规范中定义备用响应和错误码

4.4.2 防腐层的 OpenAPI 设计模式

以下示例展示了一个防腐层如何将外部遗留系统的“客户”模型转换为当前上下文所需的“用户”模型:

# anti-corruption-layer.yaml — 防腐层 API
openapi: 3.0.3
info:
  title: 客户信息防腐层
  version: 1.0.0
  description: 将遗留系统的 Customer 模型转换为当前上下文的 User 模型

paths:
  /users/{externalCustomerId}:
    get:
      tags: [ACL]
      summary: 通过外部客户ID获取内部用户信息
      parameters:
        - name: externalCustomerId
          in: path
          required: true
          schema:
            type: string
            pattern: '^CUST-\d{6}$'
      responses:
        '200':
          description: 成功转换的用户信息
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InternalUser'
        '502':
          description: 外部系统不可用
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  schemas:
    InternalUser:
      type: object
      properties:
        userId:
          type: string
          description: 内部用户ID(由ACL生成)
        displayName:
          type: string
          description: 从外部 Customer.name 转换而来
        email:
          type: string
          format: email
        roles:
          type: array
          items:
            type: string
          description: 从外部 Customer.type 映射的角色
      required: [userId, displayName, email]

    ErrorResponse:
      type: object
      properties:
        code:
          type: string
          example: 'EXTERNAL_SERVICE_UNAVAILABLE'
        message:
          type: string
          example: '无法连接到遗留客户系统,请稍后重试'
防腐层(ACL)架构模式 遗留系统 Customer 模型 name, type, phone SOAP/XML 协议 防腐层(ACL) 模型翻译 协议适配 数据验证 缓存与降级 订单上下文 User 模型 userId, displayName REST/JSON 协议 原始数据 (XML) 转换后数据 (JSON) 防腐层核心价值 1. 隔离外部系统的模型变化,保护内部模型的纯净性 2. 当外部系统升级或替换时,只需修改防腐层,内部上下文无需变更

4.5 限界上下文与 OpenAPI 规范的最佳实践

  1. 按上下文拆分 API 规范文件:每个限界上下文拥有独立的 OpenAPI 文件,通过 $ref 引用共享内核
  2. 使用标签分组:在 tags 中明确标注每个端点所属的上下文
  3. 定义上下文边界文档:在 info.description 中描述该上下文的职责和边界
  4. 防腐层独立部署:将 ACL 作为独立的 API 网关或 BFF 服务,拥有自己的 OpenAPI 规范
  5. 共享内核版本管理:使用语义化版本号,并在 info.version 中标注
总结:限界上下文是 DDD 和 API 设计的基石。通过上下文映射图理清系统间的协作关系,利用共享内核减少重复定义,借助防腐层保护内部模型的纯净性。在 OpenAPI 规范中,这些模式可以通过文件拆分、标签分组和 Schema 引用等机制优雅地实现。