Spring Axon使用无参数构造函数隐式实例化另一个聚合

Spring Axon使用无参数构造函数隐式实例化另一个聚合,spring,domain-driven-design,aggregate,event-sourcing,axon,Spring,Domain Driven Design,Aggregate,Event Sourcing,Axon,我只是想知道为什么Axon隐式地实例化另一个聚合。这种行为会导致多个事件处理,我认为这不是预期的开销。 具有此端点: @PostMapping("ship") public void shipOrder(@RequestBody Product product) { String orderId = UUID.randomUUID().toString(); commandGateway.sendAndWait(new PlaceOrderCommand(orde

我只是想知道为什么Axon隐式地实例化另一个聚合。这种行为会导致多个事件处理,我认为这不是预期的开销。 具有此端点:

@PostMapping("ship")
public void shipOrder(@RequestBody Product product) {
        String orderId = UUID.randomUUID().toString();
        commandGateway.sendAndWait(new PlaceOrderCommand(orderId, product.getName()));
        commandGateway.sendAndWait(new ConfirmOrderCommand(orderId));
}
及以下合计:

@Aggregate
public class Order {

    @AggregateIdentifier
    private String orderId;
    private boolean orderConfirmed;

    @CommandHandler
    public Order(PlaceOrderCommand command) {
        System.out.println("Calling COMMAND constructor");
        apply(new OrderPlacedEvent(command.getOrderId(), command.getProduct()));
    }

    protected Order() {
        System.out.println("Calling PARAMLESS constructor");
    }

    @CommandHandler
    public void handle(ConfirmOrderCommand command) {
        apply(new OrderConfirmedEvent(command.getOrderId()));
    }

    @EventSourcingHandler
    public void on(OrderPlacedEvent event) {
        System.out.println(">>>>>> Handling OrderPlacedEvent: " + this);
        this.orderId = event.getOrderId();
        orderConfirmed = false;
    }

    @EventSourcingHandler
    public void on(OrderConfirmedEvent event) {
        System.out.println(">>>>>> Handling OrderConfirmedEvent: " + this);
        orderConfirmed = true;
    }
}
获取此日志后调用endpoint后:

Calling COMMAND constructor
>>>>>> Handling OrderPlacedEvent: Order@3eecb9e2
Calling PARAMLESS constructor
>>>>>> Handling OrderPlacedEvent: Order@cd10277
>>>>>> Handling OrderConfirmedEvent: Order@cd10277

正如您所见,OrderPlacedEvent被调用了两次,同时调用了不带参数的构造函数。有人知道我为什么会出现以下行为吗?

当您使用事件源时,这种行为是正确的,也是预期的。在事件源中,无论何时向聚合发送命令,它都将首先加载所有以前的事件,以使聚合水合并确定其当前状态。这些事件是你的穿越之源。除了某些异常外,聚合的当前状态未存储

因此,一般来说,您应该确保只在聚合中使用
EventSourcingHandler
来填充其状态


请注意,一旦系统大量增长,聚合可能会有大量需要读取的事件。如果发生这种情况,您可以通过在每个
n
事件之后存储聚合的快照(它的当前状态)来进行一些优化。这样,您不必加载超过
n
个事件。

因此,每当我使用1-param-constructor通过命令创建聚合时,Axon会创建一个空实例,然后应用所有事件,即使存储中没有事件?此外,它是构造函数,因此我认为应该很明显,此聚合尚未存储任何事件。Axon在第一次收到该命令以及创建聚合时,使用带有命令参数的构造函数(
PlaceOrderCommand
)。尚未从事件存储中读取任何内容。在任何后续命令上,第一个命令不再存在。同样地,no-args构造函数被用来创建对象,所有事件都从eventstore中重放。我想我终于明白了它是如何工作的。假设添加第三个命令,则将创建第三个聚合实例(使用空构造函数),并处理所有后续事件。我很确定Axon会重用内存中加载的聚合实例,只应用新事件。太好了,谢谢你的充分解释!