为什么需要 EventSourcingHandler(在聚合对象中)?

Why is EventSourcingHandler (in aggregate object) needed?

公平警告:我不知道自己在做什么,所以即使问这个问题也可能出错。

我想更新一个简单对象(聚合)的状态,然后向 UI 提供已更改对象的投影。这是我的聚合对象(存在命令处理程序,但未在此处显示)。

@Aggregate
public class Widget {
    @AggregateIdentifier
    private String id;
    private String color;
...
    @EventSourcingHandler
    public void on(ChangeColorEvt evt) {
        color = evt.getColor();
    }
... 
}

...这是我的预测:

public class WidgetProjection {
    private final EntityManager entityManager;
    private final QueryUpdateEmitter queryUpdateEmitter;
...
    @EventHandler
    public void on(ChangeColorEvt evt) {
        ProjectedWidget projection = entityManager.find(ProjectedWidget.class, evt.getId());
        projection.setColor(evt.getColor());
        queryUpdateEmitter.emit(FetchWidget.class, query -> evt.getId().startsWith(query.getFilter().getIdStartsWith()), projection);
    }
...
}

QueryHandler 执行您期望的操作,找到实例并返回它。

所以这是我的问题:

  1. 为什么我需要聚合中的 EventSourcingHandler?这就对了 似乎可以工作,但结果不会存储或发送到任何地方。
  2. 所以,这成为我的下一个问题:执行 EventSourcing 之后 Handler,是 Widget 的结果实例(不是投影) 存储、查看或发送到任何地方?
  3. 如果确实需要EventSourcingHandler,有没有办法避免 有两个独立的业务逻辑副本(一个在 EventSourcingHandler 和一个 EventHandler)?我真的很讨厌这个主意 必须在两个地方更新相同的业务逻辑。

我感谢该小组提供的任何清晰信息。感谢您的帮助!

希望能帮到你解决这个问题!

简短的回答是: 使用 @EventSourcingHandler 的必要性实际上取决于您希望如何为应用程序建模。

现在,这并没有说明什么,所以让我详细说明一下我为什么要这么说。 在回答您的问题时,我假设您希望创建一个遵循 DDD、CQRS 和事件溯源思想的应用程序。因此,Axon 在构建您的应用程序时试图为您简化的概念。

让我从这里回顾一下你的编号问题:

  1. 您在聚合中需要 @EventSourcingHandler 注释函数的原因是 (1) 根据 具有的 (2) 个事件更新聚合状态出版。要转到第 1 点,为什么要更新聚合的状态?由于聚合是应用程序的命令模型,因此它的任务是根据收到的命令做出决策。为了能够做出决定,有时聚合需要状态,但有时不需要。因此,在您共享的 Widget 示例中,我假设 color 字段根本不用于稍后驱动业务逻辑,因此您可以完全从聚合中省略此状态,而无需任何问题。对于我回应的第二点,我试图指出聚合只会处理源自其自身的事件。这是因为事件是聚合的来源,因为事件构成了给定模型上发生的所有增量。
  2. 你的以下问题非常适合继续我在第 1 点开始的解释。答案很简单,你的 Widget 聚合没有存储在任何地方,而不是 原样。每次您从 Repository 检索聚合(这在 Axon 中自动为您完成),在 Axon 中默认为 EventSourcingRepository,该给定聚合的所有事件都将从活动商店。然后,创建一个 empty 聚合实例,框架将重播它为该聚合实例找到的所有事件。因此,每次收到新命令时,您都在有效地对聚合进行事件溯源。这听起来有点矫枉过正,因为给定聚合的事件数量可能会增长到相当大的集合。这可以通过做聚合的 snapshots 之类的事情来解决。
  3. 如果这种形式将您的应用程序拆分为处理您的业务逻辑的专用部分、命令模型,以及仅 returns 作为答案的查询模型的部分,即查询模型,那么您可以决定要 State Stored Aggregate。所以请注意,在使用 Axon 时,您根本不需要进行事件溯源;这只是框架的默认操作方式。因此,我理解您的担忧,即您在重复您的逻辑。但是,您可以严格分离做出所有决定的部分,这些决定将保存在您的聚合中。 查询模型(在您的示例中为 ProjectedWidget)可以以您想要的任何格式和 database/tool 存储,理想情况下没有任何业务逻辑。 如果您确实发现自己在应用程序的查询端添加业务逻辑,这可能建议您应该将此位升级为源自聚合的事件。

我希望这能让您深入了解为什么要开始使用事件溯源。本文介绍了 CQRS in a little more detail than I could do here, and this link 事件溯源;希望它们可以作为比我刚才给你的解释更彻底的解释。