应用事件后,聚合标识符必须为非null。确保汇总标识符已最晚初始化

时间:2019-10-04 20:14:54

标签: axon

我收到以下错误。 Axon版本3.3.3

  

org.axonframework.eventsourcing.IncompatibleAggregateException:   应用事件后,聚合标识符必须为非null。使   确保聚合标识符最迟在何时初始化   处理创建事件。

我已经创建了一个UserAggregate。它包含2个事件:

  • UserCreated
  • UpdateUserEvent

我能够生成第一个(UserCreated)事件,它以序列0保存在事件存储中,但是在生成第二个事件时,出现了上述错误。

对此有何建议?

UserAggregate.java

@Aggregate
public class UserAggregate {

    @AggregateIdentifier
    private String id;


    private String email;
    private String password;

    public UserAggregate(String id, String email, String password) {
        super();
        this.id = id;
        this.email = email;
        this.password = password;
    }

    @CommandHandler
    public UserAggregate(CreateUser cmd) {
         AggregateLifecycle.apply(new UserCreated(cmd.getId(), cmd.getEmail(), cmd.getPassword()));
    }

    @CommandHandler
    public void handle(UpdateUserCmd cmd) {
         AggregateLifecycle.apply(new UpdateUserEvent(cmd.getId(), cmd.getEmail(),""));
    }

    @EventSourcingHandler
    public void userCreated(UserCreated event) {

        System.out.println("new User: email " + event.getEmail() +" Password: "+ event.getPassword());

        setId(event.getId());




    }

    @EventSourcingHandler
    public void updateUserEvent(UpdateUserEvent event) {

        System.out.println("new User: email " + event.getEmail());

        setId(event.getId());




    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public UserAggregate() {
    }

}

3 个答案:

答案 0 :(得分:0)

当遵循聚合的事件源范例时,我通常建议在代码中出现两种类型的构造函数:

  1. 默认的无参数构造函数,其中没有设置。
  2. 一个(或多个)构造函数来处理“聚合创建命令”

在您的示例中,我看到了第三个构造函数,用于设置chmodidemail。 我的猜测是,此构造函数当前可能会妨碍password实现以进行正确的验证。

如果未在构造函数命令处理程序之后设置EventSourcedAggregate带注释的字段 ,则您收到的异常将仅发生(在您的情况下为{{1} }结束了它的工作单元。 因此,看到您的代码,我唯一的直觉是这个“野生的,未使用的”构造函数,它可能会阻塞事物。

最后,我需要推荐您使用更新版本的Axon。 3.3.3与当前版本4.2相距甚远。 此外,Axon 3.x版本未进行任何积极的开发。 因此,明智的做法是升级版本,因为您仍在定义命令模型,所以我认为这没什么大不了的。


更新

我刚刚关闭了您打开的Framework问题。 Axon提供了完全不同的方式来绑定Message的调度和处理,为您提供比(Spring)AOP更清晰的拦截点。

如果您遵循建议的准则,在@AggregateIdentifier中使用UserAggregate(CreateUser) / MessageDispatchInterceptor或更细粒度的选项,则可以解决您正在寻找的跨领域问题。 / p>

就日志记录而言,该框架甚至提供了MessageHandlerInterceptor来执行您需要的操作。不需要AOP。

希望这可以帮助您解决Narasimha。

答案 1 :(得分:0)

我仍然逐渐了解Axon,但这是我设法解决此问题的方法。基本上,错误是指在实例化UserAggregate时,聚合标识符(即主键)不能为null,并且必须具有值。

生命周期的顺序是

  1. 它调用no args构造函数
  2. 在您的情况下,它将使用您的初始命令调用构造函数。此时,您的集合标识符仍然为空,我们将在下一步中分配一个值
  3. 然后它调用EventSourcingHandler来处理上一步中应用的事件

根据上述步骤,您需要执行以下操作:

  1. 创建一个无参数的构造函数

protected UserAggregate() {

}
  1. 创建一个处理您的第一个命令的构造函数:

@CommandHandler
public UserAggregate(CreateUser cmd) {
    AggregateLifecycle.apply(
         new UserCreated(cmd.getId(),cmd.getEmail(),cmd.getPassword()));
}
  1. 最后添加一个事件源处理程序以处理UserCreated事件

@EventSourcingHandler
public void on(UserCreated userCreated) {

    // this is where we instantiate the aggregate identifier
    this.id = userCreated.getId();
    
    //assign values to other fields
    this.email = userCreated.getEmail();
    this.password = userCreated.getPassword();

}

这是完整的示例:


@Aggregate
public class UserAggregate {

    @AggregateIdentifier
    private String id;

    private String password;

    private String email;

    protected UserAggregate() {

    }

    @CommandHandler
    public UserAggregate(CreateUser cmd) {
        AggregateLifecycle.apply(
            new UserCreated(cmd.getId(),cmd.getEmail(),cmd.getPassword()));
    }

    @EventSourcingHandler
    public void on(UserCreated userCreated) {

        // this is where we instantiate the aggregate identifier
        this.id = userCreated.getId();

        //assign values to other fields
        this.email = userCreated.getEmail();
        this.password = userCreated.getPassword();

    }
}

答案 2 :(得分:-1)

谢谢@Steven的回复。

我也可以使用Axon 4.2(最新)版本重现此问题。 在我的项目中删除以下AOP代码后,该问题会自动解决。 看起来Axon缺少与AOP功能的兼容性。

AOP代码:

2019-10-07 12:52:41.689  WARN 31736 --- [ault-executor-0] o.a.c.gateway.DefaultCommandGateway      : Command 'com.ms.axonspringboot.commands.UpdateUserCmd' resulted in org.axonframework.commandhandling.CommandExecutionException(Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.)
2019-10-07 12:52:41.710 ERROR 31736 --- [nio-7070-exec-3] o.a.c.c.C.[.[.[.[dispatcherServlet]      : Servlet.service() for servlet [dispatcherServlet] threw exception

org.axonframework.axonserver.connector.command.AxonServerRemoteCommandHandlingException: An exception was thrown by the remote message handling component: Aggregate identifier must be non-null after applying an event. Make sure the aggregate identifier is initialized at the latest when handling the creation event.
    at org.axonframework.axonserver.connector.ErrorCode.lambda$static$8(ErrorCode.java:84) ~[axon-server-connector-4.2.jar:4.2]
    at org.axonframework.axonserver.connector.ErrorCode.convert(ErrorCode.java:180) ~[axon-server-connector-4.2.jar:4.2]

Axon 4.2版本错误日志

posts.forEach