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

时间:2019-02-28 20:25:16

标签: java axon

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

我想更新一个简单对象(聚合)上的状态,然后为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. 为什么我需要在Aggregate中使用EventSourcingHandler?这就对了 似乎可以正常工作,但结果并未存储或发送到任何地方。
  2. 因此,这成为我的下一个问题:执行EventSourcing之后 处理程序,是Widget的实例(不是投影) 存储,查看或发送到任何地方?
  3. 如果确实需要EventSourcingHandler,有什么方法可以避免 具有我的业务逻辑的两个独立副本(其中一个 EventSourcingHandler和一个EventHandler)?我真的很讨厌这个主意 必须在两个地方更新相同的业务逻辑。

我感谢该小组可以提供的任何清晰度。感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

希望我能帮助您解决这个问题!

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

现在,这没什么多说的,所以让我详细说明为什么要说明这一点。 在回答您的问题时,我假设您的愿望是创建一个应用程序,在其中遵循DDD,CQRS和事件源的思想。因此,Axon在构建应用程序时会尝试为您简化的概念。

让我从这里浏览您编号的问题:

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

我希望这能为您带来一些了解,为什么您首先要进行事件采购。本文比我在这里更详细地描述了State Stored Aggregate,并提供了CQRS的事件源链接;希望他们可以提供比我刚刚给您的更详尽的解释。