领域事件

领域事件是一个领域模型中极其重要的部分,用来表示领域中发生的事件。忽略不相关的领域活动,同时明确领域专家要跟踪或希望被通知的事情,或与其他模型对象中的状态更改相关联。

如何识别领域事件

在做用户旅程或者场景分析时,我们要捕捉业务、需求人员或领域专家口中的关键词:“如果发生……,则……”“当做完……的时候,请通知……”“发生……时,则……”等。在这些场景中,如果发生某种事件后,会触发进一步的操作,那么这个事件很可能就是领域事件。

那领域事件为什么要用最终一致性,而不是传统 SOA 的直接调用的方式呢?

聚合的一个设计原则:在边界之外使用最终一致性。一次事务最多只能更改一个聚合的状态。如果一次业务操作涉及多个聚合状态的更改,应采用领域事件的最终一致性。

领域事件驱动设计可以切断领域模型之间的强依赖关系,事件发布完成后,发布方不必关心后续订阅方事件处理是否成功,这样可以实现领域模型的解耦,维护领域模型的独立性和数据的一致性。在领域模型映射到微服务系统架构时,领域事件可以解耦微服务,微服务之间的数据不必要求强一致性,而是基于事件的最终一致性。

创建领域事件

当用户下单之后,订单系统将发出一个“用户已下单”的领域事件,并发布到消息系统中,此时下单便完成了。账户系统订阅了消息系统中的“用户已下单”事件,当事件到达时进行处理,提取事件中的订单信息,再调用自身的积分引擎(也有可能是另一个微服务)计算积分,最后更新用户积分。可以看到,此时的订单系统在发送了事件之后,整个用例操作便结束了,根本不用关心是谁收到了事件或者对事件做了什么处理。事件的消费方可以是账户系统,也可以是任何一个对事件感兴趣的第三方,比如物流系统。由此,各个微服务之间的耦合关系便解开了。值得注意的一点是,此时各个微服务之间不再是强一致性,而是基于事件的最终一致性。

事件发布的内容包括:事件名称、发布者、发布时间与相关的数据。譬如,当用户下单以后,发布这样一个领域事件:

{ event_id: “createOrder”, publisher: “service_order”, publish_time: “2021-01-07 18:38:00.000”, data: { id: “300001”, customer_id: “200005”, … } }

事件发布者要在方法的最后完成一个事件的发布。至于到底要做什么事件,交由底层技术中台去定义,比如发送消息队列,或者写入领域事件表中。例如,在“订单系统”中完成事件发布:

@Override
 public void createOrder(Order order) {
  ...
  createOrderEvent.publish(serviceName, order);
 }
 @Override
 public void modifyOrder(Order order) {
  ...
  modifyOrderEvent.publish(serviceName, order);
}

接着,事件订阅者需要为每一个事件编写相应的领域事件类,在 apply() 方法中定义该事件需要做什么操作

public class CreateOrderEvent implements DomainEvent<Order> {
 @Override
 public void apply(Order order) {
  ...
 }
}

results matching ""

    No results matching ""