20.3 上下文集成:领域事件、ACL 与模型演进
限界上下文之间必须交换信息,但不应共享同一套内部模型。集成边界负责翻译语言、隔离变化,并把本地事务产生的事实可靠地传播出去。
领域事件与集成事件分开
领域事件表达上下文内部已经发生的业务事实:
public record RegistrationConfirmed(
TournamentId tournamentId,
PlayerId playerId,
int confirmedCount
) implements DomainEvent {}它可以驱动同一上下文内的规则,但不一定适合作为公开消息。集成事件是面向外部消费者的稳定契约,可能隐藏内部字段、改变命名并增加版本元数据:
{
"eventType": "TournamentEntryConfirmed",
"schemaVersion": 1,
"entryId": "entry-92",
"tournamentId": "tournament-7",
"participantId": "participant-42",
"confirmedAt": "2026-08-03T10:15:30Z"
}把内部类直接序列化上 broker,会让重构字段变成跨团队破坏性变更。
事件何时发布
聚合可以在执行业务行为时记录领域事件,但外部发布应在事务成功之后,并通过 Outbox 保留可靠发布意图:
聚合产生领域事件
→ 应用服务保存聚合
→ 同一事务写 Outbox 集成事件
→ 提交后 relay 发布如果事务回滚,不能对外发布“报名已确认”。如果 relay 重复发布,消费者必须幂等。
Anti-Corruption Layer 保护本地语言
假设遗留计费系统用 ORD、CUS_NO 和状态码 7 表示已授权订单。报名上下文不应让这些概念扩散进领域模型:
final class LegacyBillingAdapter implements PaymentAuthorization {
private final LegacyBillingClient client;
public Authorization authorize(PaymentRequest request) {
LegacyOrderResponse response = client.createOrder(toLegacyOrder(request));
return switch (response.statusCode()) {
case 7 -> Authorization.approved(response.orderNo());
case 9 -> Authorization.declined(response.reasonCode());
default -> throw new BillingUnavailable();
};
}
}ACL 不只是 DTO Mapper。它还翻译错误、身份、时间、单位、幂等和一致性语义。若上游无法区分“拒绝”和“暂时不可用”,ACL 也不能凭空制造可靠语义,只能显式暴露不确定性。
Shared Kernel 要极小且共同治理
两个上下文共享少量模型或代码时,任何变化都需要共同协调。Shared Kernel 只适合真正稳定、双方共同拥有的部分,例如经过治理的标识类型或协议 schema。
把全部 common-domain 放进共享包会重新形成分布式单体。复制一个简单值类型,有时比永久共享演进成本更低。
模型会随认知演进
领域模型不是一次工作坊定稿。生产反馈可能暴露:
- 同一个词实际包含两个生命周期;
- 一个聚合因并发冲突过多需要拆分;
- 原以为最终一致的规则其实要求预留;
- 上下文之间的调用方向与团队责任不匹配;
- 支持人员需要模型中不存在的中间状态。
演进步骤可以是:
- 用实例和事故描述当前模型的失败;
- 与领域专家更新语言和不变量;
- 调整代码边界与契约;
- 用 expand–migrate–contract 迁移数据;
- 更新事件、监控、手册和团队责任;
- 删除旧语言和兼容层。
什么时候不需要完整 DDD
数据录入、简单 CRUD、短寿命内部工具或成熟通用领域,可能只需要清晰分层和模块边界。DDD 的建模投入适合业务规则复杂、语言歧义高、变化长期且错误代价大的核心领域。
不要用战术模式把简单问题复杂化,也不要因简单外围功能不需要 DDD,就否定核心领域进行深度建模的价值。
第 6 卷专业链路回顾
构造与契约
→ 需求、架构、测试、重构和交付
→ 设计原则与对象模式
→ 分层、端口和依赖规则
→ 模块化单体与服务提取
→ 韧性、一致性、部署和事件
→ AI 系统、API 契约与领域边界这条链路的共同目标是:把变化、失败和责任限制在可理解的边界内,并用测试、契约和运行反馈证明边界有效。
参考资料
- Martin Fowler, Anti-Corruption Layer
- Chris Richardson, Domain Event
- Chris Richardson, Transactional Outbox