在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
对象。 EventSourcingHandler(ESH)将针对IssuedEvt
处理该事件。然后,我们将创建一个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保留在某处,以便RedeemedEvt
的ESH对其减法运算具有正确的值。在调用ESH之间,对象状态如何以及在哪里保留?
最佳答案
当您从AnnotatedAggregate
检索Aggregate
实例时,框架在内部实例化Repository
。AnnotatedAggregate
类实现Aggregate
,Repository
接口(interface)将其强制为load(String)
操作的返回类型。
在谈论事件源时,正在使用的Repository
实现是EventSourcingRepository
,它在load(String)
上返回EventSourcedAggregate
实例(这是AnnotatedAggregate
的实现。Aggregate
接口(interface),该接口(interface)的AnnotatedAggregate
实现以及再次实现该接口(interface)的EventSourcedAggregate
定义了一个泛型。
此泛型是您的汇总实现。
当您通过EventSourcingRepository
事件采购聚合时,您的Aggregate实例将在AnnotatedAggregate
全局字段下的private T aggregateRoot
中的内存中保留。
此aggregateRoot
由EventSourcingRepository
更新,后者通过为其提供EventSourcedAggregate
流来初始化EventMessages
的状态。
顺便说一句,您为什么对@JonathanM这个确切的位感兴趣?
作为参考,这是这些类的GitHub链接:Aggregate
AnnotatedAggregate
EventSourcedAggregate
Repository
EventSourcingRepository