在 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 必须保留在某处,以便 ESH使 RedeemedEvt
的减法运算具有正确的值。
在调用 ESH 之间如何以及在何处保留对象状态?
最佳答案
框架在内部实例化 AnnotatedAggregate
当您检索Aggregate
时来自 Repository
的实例.
AnnotatedAggregate
类实现 Aggregate
,其中Repository
接口(interface)强制为 load(String)
上的返回类型操作。
当您谈论事件溯源时,Repository
正在使用的实现是 EventSourcingRepository
,在load(String)
上返回 EventSourcedAggregate
实例(这是 AnnotatedAggregate
的实现。
Aggregate
接口(interface),AnnotatedAggregate
该接口(interface)和 EventSourcedAggregate
的实现再次实现它,定义一个泛型。
此泛型是您的聚合实现。
当您通过EventSourcingRepository
对聚合进行事件溯源时,您的聚合实例保存在 AnnotatedAggregate
内存中下private T aggregateRoot
全局领域。
这个aggregateRoot
由 EventSourcingRepository
更新,它初始化 EventSourcedAggregate
的状态通过给它一个 EventMessages
的流.
顺便问一下,@JonathanM,你为什么对这一点感兴趣?
以下是这些类的 GitHub 链接,供引用:
关于java - 在调用 EventSourcingHandlers 之间如何保留实体的状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54988020/