理解@AggregateIdentifier & @TargetAggregateIdentifier

问题描述

所以我正在学习轴突框架,只是想巩固我对 @TargetAggregateIdentifier 注释的理解。

我的命令:

public class IssueCardCommand {

private String cardId;
private String versionNumber;
private Integer amount;

@TargetAggregateIdentifier
private String getAggregateIdentifier() {
    return (null != versionNumber) ? cardId + "V" + versionNumber : cardId;
    }
}

我的汇总:

@Aggregate
@Slf4j
public class GiftCard {

private String giftCardId;
private String versionNumber;
private Integer amount;

@AggregateIdentifier
private String getAggregateIdentifier() {
    return (null != versionNumber) ? giftCardId + "V" + versionNumber : giftCardId;
}

public GiftCard() {
    log.info("empty noargs constructor");
}

@CommandHandler
public GiftCard(IssueCardCommand cmd) {
    log.info("handling {}",cmd);
    //this.giftCardId = cmd.getCardId();
    //this.versionNumber = cmd.getVersionNumber();
    apply(new CardissuedEvent(cmd.getCardId(),cmd.getVersionNumber(),cmd.getAmount()));
}

@EventSourcingHandler
public void onCardissuedEvent(CardissuedEvent evt) {
    log.info("applying {}",evt);
    this.giftCardId = evt.getCardId();
    this.versionNumber = evt.getVersionNumber();
    this.amount = evt.getAmount();
    }
}

所以这一切都按预期工作,并且事件被正确存储。但是,我只想确保我正确理解 @TargetAggregateIdentifier 和 @AggregateIdentifier 注释。

所以,

@TargetAggregateIdentifier - 命令转到聚合的特定实例,因此需要告诉框架它是哪个实例,因此字段/方法上的此注释用于加载该特定聚合的事件?

我注意到,当我在构造函数的命令中没有 @TargetAggregateIdentifier 时,代码仍然有效。但是如果它在任何后续命令中丢失,它会给出错误“无效命令,它无法识别目标聚合”,我觉得这证实了我上面的理解?

@AggregateIdentifier - 这会告诉 axon 框架这是标识符,因此当引入更多命令时,它需要存储该特定聚合的事件?

如果有人能指出我的理解是否正确并评论不正确的地方,我将不胜感激,以便我能够以正确的方式使用该框架。

谢谢。

解决方法

我已经在最初发布问题的 AxonIQ 讨论平台上提供了一个 answer

因为用链接回答只会违反 SO 的礼仪,所以我也在这里回答:

我猜你的理解是正确的。但让我给你一个 该过程的简化解释,以便您可以将其与您的 目前的理解。

当您发出创建新聚合的命令 (即 由聚合的构造函数处理) 不需要 标识符。原因是您正在创建一个新实例,而不是加载 一个现有的。在这种情况下,框架只需要 聚合以创建它的实例。它可以很容易地找到 FQCN 因为它知道(从聚合期间的检查中 注册)哪个聚合可以处理这样的创建命令。那是 为什么创建没有 @TargetAggregateIdentifier 的命令只是工作 很好。

一旦创建命令被处理,聚合的状态需要是 存储在某处。

  • 对于事件源聚合,所有状态更改事件都存储在事件存储中
  • 对于状态存储聚合,整个状态存储在存储库中

在这两种情况下,框架都需要知道如何识别这些数据。 这就是 @AggregateIdentifier 的用途。它告诉框架 以可通过特定标识符识别的方式存储数据。 您可以将其视为 DB 术语中的主键。

当您向聚合的现有实例发送命令时 需要告诉这是哪个实例。您可以通过提供一个 @TargetAggregateIdentifier 。然后框架将创建一个新的 相应聚合的空实例,然后尝试加载 数据进去

  • 通过读取与该实例相关的所有过去事件来获取事件源聚合
  • 通过从存储库读取当前状态用于状态存储聚合

在这两种情况下,框架都会搜索可识别的数据 通过 @TargetAggregateIdentifier 的值。一旦汇总数据 加载后,它将继续处理命令。