在对EventSourcingHandlers的调用之间如何保持实体的状态?

时间:2019-03-04 16:58:37

标签: java kotlin persistence axon

Axon Giftcard demo中,有一个GiftCard类,其注释为@Aggregate:

@Aggregate
@Profile("command")
public class GiftCard {

    private final static Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    @AggregateIdentifier
    private String id;
    private int remainingValue;

    @CommandHandler
    public GiftCard(IssueCmd cmd) {
        log.debug("handling {}", cmd);
        if(cmd.getAmount() <= 0) throw new IllegalArgumentException("amount <= 0");
        apply(new IssuedEvt(cmd.getId(), cmd.getAmount(), cmd.getCurrency()));
    }

    @CommandHandler
    public void handle(RedeemCmd cmd) {
        log.debug("handling {}", cmd);
        if(cmd.getAmount() <= 0) throw new IllegalArgumentException("amount <= 0");
        if(cmd.getAmount() > remainingValue) throw new IllegalStateException("amount > remaining value");
        apply(new RedeemedEvt(id, cmd.getAmount()));
    }

...
    @EventSourcingHandler
    public void on(IssuedEvt evt) {
        log.debug("applying {}", evt);
        id = evt.getId();
        remainingValue = evt.getAmount();
        currency = evt.getCurrency();
        log.debug("new remaining value: {}", remainingValue);
        log.debug("new currency: {}", currency);
    }

   @EventSourcingHandler
    public void on(RedeemedEvt evt) {
        log.debug("applying {}", evt);
        remainingValue -= evt.getAmount();
        log.debug("new remaining value: {}", remainingValue);
    }
...

命令和事件类在Kotlin代码中定义:

data class IssueCmd(@TargetAggregateIdentifier val id: String, val amount: Int)
data class IssuedEvt(val id: String, val amount: Int)
data class RedeemCmd(@TargetAggregateIdentifier val id: String, val amount: Int)
data class RedeemedEvt(val id: String, val amount: Int)

让我们在命令总线上放置以下两个命令:

Command #     Command Class   id          amount
---------     -------------   -------     -------------
1             IssueCmd        QP34        123.45
2             RedeemCmd       QP34        38.10

在处理第一个命令时,IssueCmd的CommandHandler(CH)将IssuedEvt对象放在事件总线上。该事件将由IssuedEvt的EventSourcingHandler(ESH)处理。然后,我们将创建一个GiftCard实例,其中id设置为“ QP34 ”,而remainingValue设置为 123.45

在处理第二条命令时,RedeemCmd的CH将RedeemedEvt对象放在事件总线上。 ESH将为RedeeemedEvt处理该事件。然后,我们将创建一个GiftCard实例,其中id设置为“ QP34 ”,而remainingValue设置为 85.35

问题:每个事件由其指定的ESH处理后,结果对象实例如何以及在何处持久?

以前,我听到的答案是:确实没有。持久化的只是事件对象,它们保存在Axon的事件存储中。当需要对象的当前状态时,Axon告诉命令模型启动GiftCard类的实例,并从最早的事件到最新的事件都应用该事件。这是事件来源的定义。

但是,在进行事件搜索时,在处理IssuedEvt之后,必须将remainingValue中的 123.45 保留在某处,以便为{{1} },使其减法运算具有正确的值。

在两次调用ESH之间,对象状态如何以及在哪里保留?

1 个答案:

答案 0 :(得分:1)

当您从AnnotatedAggregate检索Aggregate实例时,框架在内部实例化Repository

AnnotatedAggregate类实现AggregateRepository接口将其强制执行为load(String)操作的返回类型。

在谈论事件源时,正在使用的Repository实现是EventSourcingRepository,它在load(String)上返回一个EventSourcedAggregate实例(这是一个实现AnnotatedAggregate中的一个。

Aggregate接口,该接口的AnnotatedAggregate实现和再次实现该接口的EventSourcedAggregate定义了一个泛型。

此泛型是您的总体实现。

当您通过EventSourcingRepository采购聚集体时,您的聚集实例将被保留在AnnotatedAggregate中的{strong>在内存中在{{ 1}}全球领域。

private T aggregateRootaggregateRoot更新,EventSourcingRepository通过为EventSourcedAggregate提供流来初始化EventMessages的状态。

顺便说一句,您为什么对@JonathanM这个确切的位感兴趣?

作为参考,这是这些类的GitHub链接:

  1. Aggregate
  2. AnnotatedAggregate
  3. EventSourcedAggregate
  4. Repository
  5. EventSourcingRepository