DDD-015:领域事件(Domain Event
DDD-015:领域事件(Domain Event)
15.1 领域事件的定义与用途
15.1.1 什么是领域事件?
【原理】
领域事件(Domain Event)是领域中已经发生的、对业务有重要意义的事实。它表示领域内发生的某件事情,通常会导致系统状态的改变或触发其他业务操作。
领域事件的核心特征:
- 过去时态命名:OrderCreated、PaymentReceived(表示已发生)
- 不可变性:事件一旦发生,其内容不可更改
- 业务含义:携带业务相关的数据
- 时效性:包含事件发生的时间
- 因果链:一个事件可能触发其他事件
15.1.2 领域事件 vs 系统事件
【对比分析】
| 维度 | 领域事件 | 系统事件 |
|---|---|---|
| 来源 | 业务领域 | 技术层 |
| 命名 | 业务术语(OrderCreated) | 技术术语(CacheInvalidated) |
| 消费者 | 业务模块 | 技术模块 |
| 数据 | 业务数据 | 技术数据 |
| 目的 | 业务解耦、流程协调 | 技术解耦、性能优化 |
// ✅ 领域事件:业务含义明确publicclassOrderCreatedEventextendsDomainEvent{privatefinalOrderIdorderId;privatefinalCustomerIdcustomerId;privatefinalMoneytotalAmount;privatefinalLocalDateTimecreatedAt;}// ❌ 系统事件:技术层面publicclassCacheInvalidatedEvent{privatefinalStringcacheKey;// 这是技术事件,不是领域事件}15.1.3 领域事件的用途
【核心用途】
| 用途 | 说明 | 示例 |
|---|---|---|
| 解耦聚合 | 聚合间不直接调用,通过事件通信 | 下单后扣库存 |
| 状态同步 | 跨聚合、跨系统状态同步 | 订单完成后更新用户积分 |
| 触发流程 | 启动后续业务流程 | 支付成功后触发发货 |
| 审计追踪 | 记录业务操作历史 | 记录所有订单状态变更 |
| 通知 | 通知外部系统或用户 | 订单取消后发送短信 |
15.2 领域事件的命名与设计
15.2.1 命名规范
【代码示例】
// ✅ 正确命名:过去时 + 业务对象 + 动作OrderCreatedEvent// 订单已创建PaymentReceivedEvent// 支付已收到OrderShippedEvent// 订单已发货CustomerUpgradedEvent// 客户已升级InventoryReservedEvent// 库存已预留// ❌ 错误命名CreateOrderEvent// 应该是过去时OrderCreateEvent// 应该是过去时OrderEvent// 太模糊,不明确发生了什么OrderStatusChangedEvent// 可以接受,但更具体更好15.2.2 事件内容设计
【代码示例】
/** * 订单已创建事件 */publicclassOrderCreatedEventextendsDomainEvent{// ========== 事件标识 ==========privatefinalStringeventId;// 事件唯一IDprivatefinalLocalDateTimeoccurredOn;// 事件发生时间privatefinalStringeventType="OrderCreated";// 事件类型// ========== 业务数据 ==========privatefinalOrderIdorderId;// 聚合IDprivatefinalCustomerIdcustomerId;// 客户IDprivatefinalMoneytotalAmount;// 订单金额privatefinalList<OrderItemInfo>items;// 商品列表摘要// ========== 元数据 ==========privatefinalStringtriggeredBy;// 触发者privatefinalintversion=1;// 事件版本// 构造函数publicOrderCreatedEvent(OrderIdorderId,CustomerIdcustomerId,MoneytotalAmount,List<OrderItemInfo>items,StringtriggeredBy){this.eventId=UUID.randomUUID().toString();this.occurredOn=LocalDateTime.now();this.orderId=orderId;this.customerId=customerId;this.totalAmount=totalAmount;this.items=newArrayList<>(items);this.triggeredBy=triggeredBy;}// Getters(不提供Setters,保证不可变)publicStringgetEventId(){returneventId;}publicLocalDateTimegetOccurredOn(){returnoccurredOn;}publicOrderIdgetOrderId(){returnorderId;}publicCustomerIdgetCustomerId(){returncustomerId;}publicMoneygetTotalAmount(){returntotalAmount;}publicList<OrderItemInfo>getItems(){returnCollections.unmodifiableList(items);}publicStringgetTriggeredBy(){returntriggeredBy;}publicStringgetEventType(){returneventType;}publicintgetVersion(){returnversion;}}/** * 订单商品信息(值对象) */publicclassOrderItemInfoimplementsSerializable{privatefinalProductIdproductId;privatefinalStringproductName;privatefinalintquantity;// 构造函数、Getters...}15.3 事件的发布与订阅
15.3.1 事件基类设计
【代码示例】
/** * 领域事件基类 */publicabstractclassDomainEventimplementsSerializable{privatestaticfinallongserialVersionUID=1L;// 事件唯一标识protectedStringeventId;// 事件发生时间protectedLocalDateTimeoccurredOn;// 事件类型(默认取类名)protectedStringeventType;// 事件版本(用于兼容性)protectedintversion=1;protectedDomainEvent(){this.eventId=UUID.randomUUID().toString();this.occurredOn=LocalDateTime.now();this.eventType=this.getClass().getSimpleName();}// GetterspublicStringgetEventId(){returneventId;}publicLocalDateTimegetOccurredOn(){returnoccurredOn;}publicStringgetEventType(){returneventType;}publicintgetVersion(){returnversion;}/** * 转换为JSON字符串(用于序列化) */publicStringtoJson(){try{ObjectMappermapper=newObjectMapper();mapper.registerModule(newJavaTimeModule());returnmapper.writeValueAsString(this);}catch(JsonProcessingExceptione){thrownewRuntimeException("Failed to serialize event",e);}}}/** * 领域事件发布者接口 */publicinterfaceDomainEventPublisher{/** * 发布单个事件 */voidpublish(DomainEventevent);/** * 批量发布事件 */voidpublishAll(List<DomainEvent>events);}/** * 领域事件订阅者接口 */publicinterfaceDomainEventSubscriber<TextendsDomainEvent>{/** * 处理事件 */voidhandle(Tevent);/** * 订阅的事件类型 */Class<T>subscribedToEventType();}15.3.2 聚合根支持事件发布
【代码示例】
/** * 聚合根基类 - 支持领域事件 */publicabstractclassAggregateRoot<IDextendsIdentifier>extendsEntity<ID>{// 暂存的领域事件privatefinalList<DomainEvent>domainEvents=newArrayList<>();protectedAggregateRoot(IDid){super(id);}/** * 注册领域事件 */protectedvoidregisterEvent(DomainEventevent){this.domainEvents.add(event);}/** * 获取所有领域事件(只读) */publicList<DomainEvent>getDomainEvents(){returnCollections.unmodifiableList(domainEvents);}/** * 是否有领域事件 */publicbooleanhasDomainEvents(){return!domainEvents.isEmpty();}/** * 清空领域事件(发布后调用) */publicvoidclearDomainEvents(){this.domainEvents.clear();}}/** * 订单聚合根 - 发布事件 */publicclassOrderextendsAggregateRoot<OrderId>{privateOrderIdid;privateOrderStatusstatus;privateMoneytotalAmount;// 创建订单publicstaticOrdercreate(CustomerIdcustomerId){Orderorder=newOrder(OrderId.generate(),customerId);order.registerEvent(newOrderCreatedEvent(order.id,customerId,order.totalAmount,Collections.emptyList(),"system"));returnorder;}