java - 在对 EventSourcingHandlers 的调用之间,实体的状态如何保持?
问题描述
在Axon Giftcard 演示中,有一个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
在处理第一个命令时,CommandHandler (CH)IssueCmd
将把一个IssuedEvt
对象放在事件总线上。该事件将由 EventSourcingHandler (ESH) 为IssuedEvt
. 然后,我们将设置为“ QP34 ”并GiftCard
设置为123.45的实例。id
remainingValue
在处理第二个命令时,CH forRedeemCmd
会将一个RedeemedEvt
对象放在事件总线上。该事件将由 ESH 为RedeeemedEvt
. 然后我们将有一个GiftCard
withid
设置为“ QP34 ”并remainingValue
设置为85.35的实例。
问题:在每个事件都由其指定的 ESH 处理后,生成的对象实例如何以及在何处持续存在?
以前,我听到的答案是:确实没有。所有持续存在的都是事件对象,它们保存在 Axon 的事件存储中。当需要一个对象的当前状态时,Axon 告诉命令模型启动GiftCard
该类的一个实例,并将事件从最早到最晚应用到它。这是事件溯源的定义。
但是,在IssuedEvt
处理事件溯源时,必须将123.45 inremainingValue
保留在某处,以使 ESH 的RedeemedEvt
减法运算具有正确的值。
在对 ESH 的调用之间,对象状态如何以及在何处保持?
解决方案
当AnnotatedAggregate
您Aggregate
从Repository
.
该类AnnotatedAggregate
实现了Aggregate
,Repository
接口强制将其作为load(String)
操作的返回类型。
当您谈论事件溯源时,Repository
正在使用的实现是EventSourcingRepository
,它在 a 上load(String)
返回一个EventSourcedAggregate
实例(这是AnnotatedAggregate
.
Aggregate
接口,该接口AnnotatedAggregate
的实现以及实现该接口的EventSourcedAggregate
再次定义一个泛型。
这个泛型是您的聚合实现。
当您通过 对聚合进行事件溯源时EventSourcingRepository
,您的聚合实例将保存在全局字段下的内存中。AnnotatedAggregate
private T aggregateRoot
这aggregateRoot
是由 更新的,它通过给它一个流来EventSourcingRepository
初始化你的状态。EventSourcedAggregate
EventMessages
顺便说一句,你为什么对这个确切的位感兴趣,@JonathanM?
作为参考,这里是这些类的 GitHub 链接:
推荐阅读
- amazon-web-services - React Router DOM 在 Amplify 控制台 AWS 上无法正常工作
- c++ - CMake无法从子文件夹中找到包含文件
- c# - ML.NET 绘制 K 均值聚类结果?
- z3 - 变量的初始值
- python - 为什么我的 django 分页不断返回相同的项目?
- java - 已解决:带有 TabLayout 和 FragmentPagerAdapter 和 ViewPager 的应用程序崩溃
- java - 无法解析 mojo org.apache.maven.plugins:maven-assembly-plugin:3.1.1 的配置
- regex - 使用正则表达式进行智能(迭代和增量)复制和粘贴
- python-3.x - 是否有可能将启动参数传递给 setup.py 测试
- android - 交换片段时是否需要始终重新创建片段?