求Spring Boot Microservices Saga项目可运行POC源码示例
以下提供两种主流Saga实现模式的极简可运行POC,无冗余依赖,逻辑清晰易懂,你可以直接在本地搭建运行:
1. 协同式Saga POC(基于Spring Boot + Kafka)
不需要引入额外的编排组件,通过服务之间传递事件完成流程流转,适合轻量化场景。
项目结构
- 3个独立Spring Boot微服务:订单服务、库存服务、支付服务
- 统一依赖:
spring-boot-starter-web、spring-kafka、lombok、spring-boot-starter-data-jpa、h2(内存数据库)
核心代码片段
订单服务核心逻辑
@Service public class OrderService { private final KafkaTemplate<String, Object> kafkaTemplate; private final OrderRepository orderRepository; public Order createOrder(OrderCreateDTO request) { Order order = new Order(); order.setStatus("CREATED"); order.setUserId(request.getUserId()); order.setProductId(request.getProductId()); order.setAmount(request.getAmount()); order.setTotalPrice(request.getAmount() * request.getUnitPrice()); orderRepository.save(order); // 发布订单创建事件 kafkaTemplate.send("order_created", order); return order; } // 补偿监听:取消订单 @KafkaListener(topics = "order_cancel") public void handleOrderCancel(Order order) { order.setStatus("CANCELLED"); orderRepository.save(order); } // 完成订单监听 @KafkaListener(topics = "order_complete") public void handleOrderComplete(Order order) { order.setStatus("COMPLETED"); orderRepository.save(order); } }
库存服务核心逻辑
@Service public class InventoryService { private final KafkaTemplate<String, Object> kafkaTemplate; private final InventoryRepository inventoryRepository; @KafkaListener(topics = "order_created") public void handleOrderCreate(Order order) { Inventory inventory = inventoryRepository.findByProductId(order.getProductId()); if (inventory.getStock() >= order.getAmount()) { // 扣减库存 inventory.setStock(inventory.getStock() - order.getAmount()); inventoryRepository.save(inventory); // 发布库存扣减成功事件 kafkaTemplate.send("inventory_deducted", order); } else { // 库存不足,触发订单取消补偿 kafkaTemplate.send("order_cancel", order); } } // 补偿监听:回滚库存 @KafkaListener(topics = "inventory_rollback") public void handleInventoryRollback(Order order) { Inventory inventory = inventoryRepository.findByProductId(order.getProductId()); inventory.setStock(inventory.getStock() + order.getAmount()); inventoryRepository.save(inventory); } }
支付服务核心逻辑
@Service public class PaymentService { private final KafkaTemplate<String, Object> kafkaTemplate; private final PaymentRepository paymentRepository; @KafkaListener(topics = "inventory_deducted") public void handleInventoryDeducted(Order order) { Payment payment = paymentRepository.findByUserId(order.getUserId()); if (payment.getBalance() >= order.getTotalPrice()) { // 扣减余额 payment.setBalance(payment.getBalance() - order.getTotalPrice()); paymentRepository.save(payment); // 所有步骤完成,发布订单完成事件 kafkaTemplate.send("order_complete", order); } else { // 余额不足,触发两级补偿 kafkaTemplate.send("inventory_rollback", order); kafkaTemplate.send("order_cancel", order); } } }
2. 编排式Saga POC(基于Spring Boot + Axon Framework)
由中心化编排器统一控制Saga流程和补偿逻辑,适合复杂业务场景,框架自动管理Saga生命周期和状态。
项目依赖
- 核心依赖:
spring-boot-starter-web、axon-spring-boot-starter、lombok、h2(内存数据库存储Saga状态和事件)
核心Saga编排代码
@Saga public class OrderProcessingSaga { @Autowired private transient CommandGateway commandGateway; // 订单创建事件触发Saga启动 @StartSaga @SagaEventHandler(associationProperty = "orderId") public void handleOrderCreated(OrderCreatedEvent event) { // 发送扣减库存命令 commandGateway.send(new DeductInventoryCommand( event.getOrderId(), event.getProductId(), event.getAmount() )); } // 库存扣减成功后触发扣减余额 @SagaEventHandler(associationProperty = "orderId") public void handleInventoryDeducted(InventoryDeductedEvent event) { commandGateway.send(new DeductBalanceCommand( event.getOrderId(), event.getUserId(), event.getTotalPrice() )); } // 余额扣减成功,Saga完成 @SagaEventHandler(associationProperty = "orderId") public void handleBalanceDeducted(BalanceDeductedEvent event) { commandGateway.send(new CompleteOrderCommand(event.getOrderId())); SagaLifecycle.end(); } // 库存扣减失败,直接取消订单 @SagaEventHandler(associationProperty = "orderId") public void handleInventoryDeductFailed(InventoryDeductFailedEvent event) { commandGateway.send(new CancelOrderCommand(event.getOrderId())); SagaLifecycle.end(); } // 余额扣减失败,先回滚库存再取消订单 @SagaEventHandler(associationProperty = "orderId") public void handleBalanceDeductFailed(BalanceDeductFailedEvent event) { commandGateway.send(new RollbackInventoryCommand( event.getOrderId(), event.getProductId(), event.getAmount() )); commandGateway.send(new CancelOrderCommand(event.getOrderId())); SagaLifecycle.end(); } }
上述两个POC都是最小实现,你可以直接在本地启动对应服务,分别模拟库存不足、余额不足、所有步骤正常三种场景,就能直观看到Saga的正向执行和反向补偿的完整逻辑。
内容的提问来源于stack exchange,提问作者Jeff Cook
相关产品推荐
相关产品推荐

