You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Axon向同一聚合发送多条命令仅首条被处理异常排查

问题描述

使用Axon框架向同一个聚合(Aggregate)发送多条命令时,仅第一条命令可被正常处理,第二条命令发送后抛出如下异常:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.axonframework.commandhandling.CommandExecutionException: Cannot invoke "Object.hashCode()" because "key" is null

相关实现代码

命令发送服务方法

public void maakAanvraag() {
    UUID aanvraagId = UUID.randomUUID();

    commandGateway.sendAndWait(
            VerwerkAanvraag.builder()
                    .aanvraagId(aanvraagId)
                    .build()
    );

    commandGateway.sendAndWait(
            VerwerkPersoonsgegevensVastgesteld.builder()
                    .aanvraagId(aanvraagId)
                    .build()
    );
    
    commandGateway.sendAndWait(
            VerwerkOrganisatiegegevensVastgesteld.builder()
                    .aanvraagId(aanvraagId)
                    .organisatieId(organisatieView.getOrganisatieId())
                    .rolOrganisatie(rolOrganisatie)
                    .build()
    );

    commandGateway.sendAndWait(
            VerwerkBeperkingErkenningsdoelGematcht.builder()
                    .aanvraagId(aanvraagId)
                    .build());
}

聚合类代码

@Aggregate
@Getter
@NoArgsConstructor
public class Aanvraag {

    public static final String META_DATA_ZAAKNUMMER = "aanvraag_zaaknummer";

    @AggregateIdentifier
    private UUID aanvraagId;

    @CommandHandler
    public Aanvraag(VerwerkAanvraag command) {
        AanvraagGeregistreerd aanvraagGeregistreerd =
                AanvraagGeregistreerd.builder()
                        .aanvraagId(command.getAanvraagId())
                        .build();

        apply(aanvraagGeregistreerd, MetaData.with(META_DATA_ZAAKNUMMER, "123456789"));
    }

    @EventSourcingHandler
    public void on(AanvraagGeregistreerd event) {
        aanvraagId = event.getAanvraagId();
    }

    @CommandHandler
    public void verwerkOrganisatiegegevensVastgesteld(VerwerkOrganisatiegegevensVastgesteld command) {
        OrganisatiegegevensVastgesteld persoonsgegevensVastgesteld =
                OrganisatiegegevensVastgesteld.builder()
                        .aanvraagId(command.getAanvraagId())
                        .build();
        apply(persoonsgegevensVastgesteld);
    }

    @EventSourcingHandler
    public void on(OrganisatiegegevensVastgesteld event) {
        aanvraagId = event.getAanvraagId();
    }

    @CommandHandler
    public void verwerkPersoonsgegevensVastgesteld(VerwerkPersoonsgegevensVastgesteld command) {
        PersoonsgegevensVastgesteld persoonsgegevensVastgesteld =
                PersoonsgegevensVastgesteld.builder()
                        .aanvraagId(command.getAanvraagId())
                        .build();
        apply(persoonsgegevensVastgesteld);
    }

    @EventSourcingHandler
    public void on(PersoonsgegevensVastgesteld event) {
        aanvraagId = event.getAanvraagId();
    }

    @CommandHandler
    public void verwerkBeperkingErkenningsdoelGematcht(VerwerkBeperkingErkenningsdoelGematcht command) {
        BeperkingErkenningsdoelGematcht beperkingErkenningsdoelGematcht =
                BeperkingErkenningsdoelGematcht.builder()
                        .aanvraagId(command.getAanvraagId())
                        .build();
        apply(beperkingErkenningsdoelGematcht);
    }

    @EventSourcingHandler
    public void on(BeperkingErkenningsdoelGematcht event) {
        aanvraagId = event.getAanvraagId();
    }
}

运行环境

  • Spring Boot版本:2.6.6
  • 依赖版本:axon-spring-boot-starter 4.5.9
  • JDK版本:Java Temurin 17.0.3
问题原因与修复方案

该问题不属于配置错误,是实现逻辑遗漏了必要的注解标识:

  • 聚合构造函数上的@CommandHandler用于创建全新的聚合实例,不需要路由到已存在的聚合,因此第一条命令可以正常执行。
  • 其余三个@CommandHandler标注的方法用于操作已经存在的聚合实例,Axon需要从入参命令中提取聚合ID,才能将命令路由到正确的聚合实例。当前三个命令类中承载聚合ID的aanvraagId字段没有添加@TargetAggregateIdentifier注解,Axon无法提取到路由用的聚合ID,将null作为key传入内部存储结构触发hashCode计算,最终抛出空指针异常。

修复方式:
给VerwerkPersoonsgegevensVastgesteld、VerwerkOrganisatiegegevensVastgesteld、VerwerkBeperkingErkenningsdoelGematcht三个命令类中的aanvraagId字段添加org.axonframework.modelling.command.TargetAggregateIdentifier注解即可,示例如下:

// 以VerwerkPersoonsgegevensVastgesteld为例,其余两个命令类修改逻辑一致
@Builder
public class VerwerkPersoonsgegevensVastgesteld {
    @TargetAggregateIdentifier
    private UUID aanvraagId;
    // 其余业务字段保持不变
}

如果不想修改命令类定义,也可以直接在聚合内的CommandHandler方法的命令参数上添加该注解,效果一致。


内容的提问来源于stack exchange,提问作者Jan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 12:24:25