Axon Saga中CanceledPreemptProductEvent处理器内OrderInfoDto为空问题排查
Axon Saga 状态丢失导致空指针异常问题
在Spring Boot结合Axon实现微服务架构时,遇到Saga状态丢失问题:StartedOrderSagaEvent处理器中设置的OrderInfoDto对象,在CanceledPreemptProductEvent处理器执行时变为null,触发空指针异常。已配置JPA作为Saga存储,但OrderInfoDto未被持久化到saga_entry表的serialized_saga列。
相关代码
OrderSaga.java
@Saga @ProcessingGroup("orderSagaProcessor") @Slf4j public class OrderSaga { @Transient private transient CommandGateway commandGateway; private OrderInfoDto orderInfoDto; @Autowired public void setCommandGateway(CommandGateway commandGateway) { this.commandGateway = commandGateway; } @StartSaga @SagaEventHandler(associationProperty = "orderUuid") public void handle(StartedOrderSagaEvent event) { log.info("[OrderSaga] Order Saga started for orderUuid: {}", event.getOrderUuid()); this.orderInfoDto = new OrderInfoDto(event.getOrderUuid(), event.getName(), event.getPhoneNumber(), 0, OrderState.PROCESS, null, null); } @SagaEventHandler(associationProperty = "orderUuid") public void handle(CanceledPreemptProductEvent event) { log.error("[OrderSaga] Failed preempt product for orderUuid: {}", event.getOrderUuid()); // NullPointerException occurs here because orderInfoDto is null this.orderInfoDto.getProductItems().forEach(productItem -> { commandGateway.send(new CancelPreemptionCommand(productItem.getProductUuid(), productItem.getCount())); }); } }
OrderInfoDto.java
@Getter @Setter @AllArgsConstructor @NoArgsConstructor public class OrderInfoDto implements Serializable { private String orderUuid; private String name; private String phoneNumber; private int total; private OrderState state; private List<ProductItem> productItems; private String paymentUuid; @Getter @Setter @AllArgsConstructor @NoArgsConstructor public static class ProductItem implements Serializable { private String productUuid; private int price; private int count; } }
application.yml
axon: axonserver: servers: localhost:8124 eventhandling: processors: orderSagaProcessor: mode: tracking source: eventStore orderAggregateProcessor: # Processor 이름 mode: tracking source: eventStore saga: store: jpa serializer: general: jackson events: jackson messages: jackson
疑问
- 在Saga内部以变量形式存储OrderInfoDto是否存在错误?
- 若该方式不正确,Axon Saga中持久化有状态数据的最佳实践是什么?
- 该问题是否与序列化配置(axon.serializer.general: jackson)相关?
问题解答
1. Saga内部存储OrderInfoDto的方式是否错误?
本身没有语法错误,但存在两个关键问题:
- Axon的Saga仅会在事件处理方法执行完毕后、或显式调用
SagaLifecycle#end()时持久化状态。如果StartedOrderSagaEvent处理完成后,Saga未触发持久化逻辑(比如未关联后续事件导致Saga被判定为结束),后续事件触发时就加载不到之前设置的orderInfoDto。 - 需确认
OrderState枚举是否实现了Serializable接口:如果枚举未序列化,会导致整个OrderInfoDto序列化失败,进而无法持久化。
2. Axon Saga持久化有状态数据的最佳实践
- 确保所有状态字段可序列化:所有需要持久化的Saga成员变量(包括嵌套对象、枚举)必须实现
Serializable接口。 - 依赖Axon自动持久化机制:每个
@SagaEventHandler方法执行完成后,Axon会自动持久化Saga状态;处理事件时,需通过SagaLifecycle.associateWith(...)关联后续可能触发的事件标识(你的场景中已通过associationProperty关联orderUuid,这一步没问题)。 - 标记非持久化字段:不需要持久化的字段(比如
CommandGateway)必须用transient修饰,避免序列化失败。 - 简化Saga状态:仅存储必要的核心业务数据,不要将大对象或无关数据放入Saga,减少序列化开销和存储风险。
3. 是否与Jackson序列化配置相关?
有可能,需检查以下几点:
- 枚举序列化正确性:如果
OrderState枚举有自定义逻辑,需确保Jackson能正确处理(比如添加@JsonFormat或自定义序列化器)。 - 嵌套对象与集合序列化:确认Jackson能正常序列化
List<ProductItem>这类集合类型,内部静态类ProductItem已实现Serializable,这部分基础没问题。 - 查看序列化日志:开启Axon调试日志,排查是否有序列化异常被隐藏:
若序列化失败,日志中会有明确报错,这会直接导致Saga状态无法持久化,后续加载时logging: level: org.axonframework: DEBUGorderInfoDto即为null。
内容的提问来源于stack exchange,提问作者드가자
相关产品推荐
相关产品推荐

