SpringBoot 使用Spring Statemachine(状态机)
·
使用if-else或者switch语句来处理这些状态,代码会变得非常臃肿且难以维护。而状态机提供了一种更加结构化和可维护的方式来管理这些状态转换
示例中涉及到:状态机的配置、数据持久化、状态恢复查询、同一事件由同一sourceStatus流转到不同targetStatus
1、首先,需要添加Spring Statemachine的依赖到Spring Boot项目的pom.xml文件中:
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>4.0.1</version>
</dependency>
- 定义状态和事件枚举
public enum OrderStates {
// 待支付,待发货,待收货,已完成,已取消
WAIT_PAYMENT, WAIT_DELIVER, WAIT_RECEIVE, COMPLETED, CANCELLED
}
public enum OrderEvents {
// 支付,发货,确认收货,取消订单
PAY, DELIVER, RECEIVE, CANCEL
}
- 配置状态机
@Configuration
@EnableStateMachine
public class StateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
throws Exception {
states
.withStates()
.initial(OrderStates.WAIT_PAYMENT)
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
throws Exception {
transitions
.withExternal()
.source(OrderStates.WAIT_PAYMENT).target(OrderStates.WAIT_DELIVER)
.event(OrderEvents.PAY)
.and()
.withExternal()
.source(OrderStates.WAIT_DELIVER).target(OrderStates.WAIT_RECEIVE)
.event(OrderEvents.DELIVER)
.and()
.withExternal()
.source(OrderStates.WAIT_RECEIVE).target(OrderStates.COMPLETED)
.event(OrderEvents.RECEIVE)
.and()
.withExternal()
.source(OrderStates.WAIT_PAYMENT).target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL)
.and()
.withExternal()
.source(OrderStates.WAIT_DELIVER).target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL);
}
@Override
public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config)
throws Exception {
config
.withConfiguration()
.autoStartup(true)
.listener(stateMachineListener());
}
@Bean
public StateMachineListener<OrderStates, OrderEvents> stateMachineListener() {
return new StateMachineListenerAdapter<OrderStates, OrderEvents>() {
@Override
public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
System.out.println("状态变更: " + (from == null ? "无" : from.getId()) + " -> " + to.getId());
}
@Override
public void eventNotAccepted(Message<OrderEvents> event) {
System.out.println("事件不被接受: " + event.getPayload());
}
};
}
}
- 状态机服务类
@Service
public class OrderStateMachineService {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> stateMachineFactory;
private final Map<Long, StateMachine<OrderStates, OrderEvents>> stateMachines = new ConcurrentHashMap<>();
/**
* 创建订单状态机
*/
public StateMachine<OrderStates, OrderEvents> createStateMachine(Long orderId) {
StateMachine<OrderStates, OrderEvents> stateMachine = stateMachineFactory.getStateMachine();
stateMachine.start();
stateMachines.put(orderId, stateMachine);
return stateMachine;
}
/**
* 发送事件
*/
public boolean sendEvent(Long orderId, OrderEvents event) {
StateMachine<OrderStates, OrderEvents> stateMachine = stateMachines.get(orderId);
if (stateMachine == null) {
return false;
}
return stateMachine.sendEvent(event);
}
/**
* 获取当前状态
*/
public OrderStates getCurrentState(Long orderId) {
StateMachine<OrderStates, OrderEvents> stateMachine = stateMachines.get(orderId);
return stateMachine != null ? stateMachine.getState().getId() : null;
}
/**
* 获取订单的状态机实例
*/
public StateMachine<OrderStates, OrderEvents> getStateMachine(Long orderId) {
return stateMachines.get(orderId);
}
}
- 订单实体类
@Data
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNumber;
private BigDecimal amount;
private OrderStates status;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@PrePersist
protected void onCreate() {
createTime = LocalDateTime.now();
updateTime = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updateTime = LocalDateTime.now();
}
}
- 订单服务类
@Service
@Transactional
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderStateMachineService stateMachineService;
/**
* 创建订单
*/
public Order createOrder(Order order) {
order.setStatus(OrderStates.WAIT_PAYMENT);
Order savedOrder = orderRepository.save(order);
// 创建对应的状态机
stateMachineService.createStateMachine(savedOrder.getId());
return savedOrder;
}
/**
* 支付订单
*/
public boolean payOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (stateMachineService.sendEvent(orderId, OrderEvents.PAY)) {
order.setStatus(OrderStates.WAIT_DELIVER);
orderRepository.save(order);
return true;
}
return false;
}
/**
* 发货
*/
public boolean deliverOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (stateMachineService.sendEvent(orderId, OrderEvents.DELIVER)) {
order.setStatus(OrderStates.WAIT_RECEIVE);
orderRepository.save(order);
return true;
}
return false;
}
/**
* 确认收货
*/
public boolean receiveOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (stateMachineService.sendEvent(orderId, OrderEvents.RECEIVE)) {
order.setStatus(OrderStates.COMPLETED);
orderRepository.save(order);
return true;
}
return false;
}
/**
* 取消订单
*/
public boolean cancelOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new RuntimeException("订单不存在"));
if (stateMachineService.sendEvent(orderId, OrderEvents.CANCEL)) {
order.setStatus(OrderStates.CANCELLED);
orderRepository.save(order);
return true;
}
return false;
}
/**
* 获取订单当前状态
*/
public OrderStates getOrderStatus(Long orderId) {
return stateMachineService.getCurrentState(orderId);
}
}
- 控制器
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody Order order) {
return ResponseEntity.ok(orderService.createOrder(order));
}
@PostMapping("/{orderId}/pay")
public ResponseEntity<String> payOrder(@PathVariable Long orderId) {
boolean result = orderService.payOrder(orderId);
return result ?
ResponseEntity.ok("支付成功") :
ResponseEntity.badRequest().body("支付失败,当前状态不允许支付");
}
@PostMapping("/{orderId}/deliver")
public ResponseEntity<String> deliverOrder(@PathVariable Long orderId) {
boolean result = orderService.deliverOrder(orderId);
return result ?
ResponseEntity.ok("发货成功") :
ResponseEntity.badRequest().body("发货失败,当前状态不允许发货");
}
@PostMapping("/{orderId}/receive")
public ResponseEntity<String> receiveOrder(@PathVariable Long orderId) {
boolean result = orderService.receiveOrder(orderId);
return result ?
ResponseEntity.ok("收货成功") :
ResponseEntity.badRequest().body("收货失败,当前状态不允许确认收货");
}
@PostMapping("/{orderId}/cancel")
public ResponseEntity<String> cancelOrder(@PathVariable Long orderId) {
boolean result = orderService.cancelOrder(orderId);
return result ?
ResponseEntity.ok("取消成功") :
ResponseEntity.badRequest().body("取消失败,当前状态不允许取消");
}
@GetMapping("/{orderId}/status")
public ResponseEntity<OrderStates> getOrderStatus(@PathVariable Long orderId) {
return ResponseEntity.ok(orderService.getOrderStatus(orderId));
}
}
- 测试类
@SpringBootTest
class OrderStateMachineTest {
@Autowired
private OrderService orderService;
@Test
void testOrderStateFlow() {
// 创建订单
Order order = new Order();
order.setOrderNumber("ORDER001");
order.setAmount(new BigDecimal("100.00"));
Order createdOrder = orderService.createOrder(order);
// 验证初始状态
assertEquals(OrderStates.WAIT_PAYMENT, orderService.getOrderStatus(createdOrder.getId()));
// 支付
assertTrue(orderService.payOrder(createdOrder.getId()));
assertEquals(OrderStates.WAIT_DELIVER, orderService.getOrderStatus(createdOrder.getId()));
// 发货
assertTrue(orderService.deliverOrder(createdOrder.getId()));
assertEquals(OrderStates.WAIT_RECEIVE, orderService.getOrderStatus(createdOrder.getId()));
// 确认收货
assertTrue(orderService.receiveOrder(createdOrder.getId()));
assertEquals(OrderStates.COMPLETED, orderService.getOrderStatus(createdOrder.getId()));
}
@Test
void testInvalidTransition() {
// 创建订单
Order order = new Order();
order.setOrderNumber("ORDER002");
order.setAmount(new BigDecimal("200.00"));
Order createdOrder = orderService.createOrder(order);
// 尝试从待支付直接发货(应该失败)
assertFalse(orderService.deliverOrder(createdOrder.getId()));
assertEquals(OrderStates.WAIT_PAYMENT, orderService.getOrderStatus(createdOrder.getId()));
}
}
主要是这里的
/**
* 配置状态
*
* @param states
* @throws Exception
*/
@Override
public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderEvent> states) throws Exception {
states.withStates()
.initial(OrderStatusEnum.LOAN_PENDING) // 设置初始状态为[待审核]
.states(EnumSet.allOf(OrderStatusEnum.class));
}
/**
* 配置状态转换事件关系
*
* @param transitions
* @throws Exception
*/
@Override
public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderEvent> transitions) throws Exception {
transitions
//当执行 【开始审核】操作时,将订单状态由待审核 -> 审核中
.withExternal().source(OrderStatusEnum.APPROVE_PENDING).target(OrderStatusEnum.APPROVE_ING).event(OrderEvent.APPROVE_START)
.and()
//当执行 【审核失败】操作时,将订单状态由审核中 -> 审核失败
.withExternal().source(OrderStatusEnum.APPROVE_ING).target(OrderStatusEnum.APPROVE_FAILED).event(OrderEvent.APPROVE_FAILED)
.and()
//当执行 【审核成功】操作时,将订单状态由审核中 -> 审核成功
.withExternal().source(OrderStatusEnum.APPROVE_ING).target(OrderStatusEnum.APPROVE_SUCCESS).event(OrderEvent.APPROVE_SUCCESS);
}
/**
* 持久化配置
*
* @return
*/
@Bean
public DefaultStateMachinePersister persister() {
return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatusEnum, OrderEvent, BizOrder>() {
@Override
public void write(StateMachineContext<OrderStatusEnum, OrderEvent> context, BizOrder order) throws Exception {
OrderStatusEnum orderStatus = context.getState();
log.info("订单状态持久化,订单ID:{},目标状态:{}", order.getId(), orderStatus);
orderMapper.updateOrderStatus(order.getId(), orderStatus);
}
@Override
public StateMachineContext<OrderStatusEnum, OrderEvent> read(BizOrder order) throws Exception {
log.info("恢复订单状态机状态");
return new DefaultStateMachineContext<>(order.getStatus(), null, null, null);
}
});
}
}
优化一下上面的【配置状态转换事件关系】,需要在事件后面增加条件判断(通过guard()实现)
/**
* 配置状态转换事件关系
*
* @param transitions
* @throws Exception
*/
@Override
public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderEvent> transitions) throws Exception {
transitions
//当执行 【开始审核】操作时,将订单状态由待审核 -> 审核中
.withExternal().source(OrderStatusEnum.APPROVE_PENDING).target(OrderStatusEnum.APPROVE_ING).event(OrderEvent.APPROVE_START)
.and()
//当执行 【审核失败】操作时,将订单状态由审核中 -> 审核失败
.withExternal().source(OrderStatusEnum.APPROVE_ING).target(OrderStatusEnum.APPROVE_FAILED).event(OrderEvent.APPROVE_FAILED)
.and()
//当执行 【审核成功】操作时,将订单状态由审核中 -> 审核成功
.withExternal().source(OrderStatusEnum.APPROVE_ING).target(OrderStatusEnum.APPROVE_SUCCESS).event(OrderEvent.APPROVE_SUCCESS)
.and()
//当执行 【放款】操作时,将订单状态由审核成功 -> 放款成功
.withExternal().source(OrderStatusEnum.APPROVE_SUCCESS).target(OrderStatusEnum.LOAN_SUCCESS).event(OrderEvent.LOAN).guard(guardForLoanSuccessByLoan())
.and()
//当执行 【放款】操作时,将订单状态由审核成功 -> 部分放款成功
.withExternal().source(OrderStatusEnum.APPROVE_SUCCESS).target(OrderStatusEnum.PARTIALLY_LOAN_SUCCESS).event(OrderEvent.LOAN).guard(guardForPartiallyLoanSuccessByLoan());
}
/**
* 订单状态由审核通过 -> 放款成功
* 触发条件:订单申请金额=放款金额
*
* @return
*/
@Bean
public Guard<OrderStatusEnum, OrderEvent> guardForLoanSuccessByLoan() {
return context -> {
// 从扩展信息中获取参数
StateMachineParam param = (StateMachineParam) context.getExtendedState().getVariables().get("param");
BizOrder order = param.getBizOrder();
// 如果申请金额=放款金额 ,返回true,状态机就会流转到调用此方法的目标状态
if (order.getApplyAmount().compareTo(order.getLoanAmlunt) == 0) {
return true;
}
return false;
};
}
/**
* 订单状态由审核通过 -> 部分放款成功
* 触发条件:订单申请金额<放款金额
*
* @return
*/
@Bean
public Guard<OrderStatusEnum, OrderEvent> guardForPartiallyLoanSuccessByLoan() {
return context -> {
// 从扩展信息中获取参数
StateMachineParam param = (StateMachineParam) context.getExtendedState().getVariables().get("param");
BizOrder order = param.getBizOrder();
// 如果申请金额<放款金额 ,返回true,状态机就会流转到调用此方法的目标状态
if (order.getApplyAmount().compareTo(order.getLoanAmlunt) < 0) {
return true;
}
return false;
};
}
更多推荐




所有评论(0)