> 技术文档 > Spring状态机 Statemachine使用_spring 状态机

Spring状态机 Statemachine使用_spring 状态机

目录

1. 状态机简介

2. 核心组件介绍

2.1 流转逻辑相关:

2.2 业务逻辑组件:

2.3 流程示例图

3. 示例代码

3.1 依赖引入

3.2 状态枚举定义

3.3 事件枚举定义

3.4 配置类

3.5 Guard--存放业务检查逻辑

 3.6 Action---存放业务执行逻辑

3.7 核心控制类

3.8 监听器  

3.9 持久化

4. 总结


1. 状态机简介

        状态机(State Machine)是一种描述系统行为的数学模型,核心思想是将系统抽象为有限个状态,并通过状态转移规则定义系统如何响应外部事件。它由一系列状态(States)、转换(Transitions)、事件(Events)、卫兵(Guards)和动作(Actions)组成。在软件开发中,状态机常用于控制程序的流程和状态变化。

        其核心优势在于: 通过清晰明确的状态定义、自动状态更新,将复杂的状态流转逻辑结构化从而使得业务逻辑与状态解耦,减少了自己维护状态产生的大量if-else,显著提升代码可维护性和扩展性​​。

2. 核心组件介绍

2.1 流转逻辑相关:

组件​

处理逻辑类型​

State枚举

枚举对象所有的状态(流程图的节点)

Events枚举

枚举所有引起两个状态之间切换的事件(流程图的箭头)

Configurer配置类

组装State和Event的转换关系 (相当于流程图)

StateMachine状态机 一个状态机表征一个对象实体,它拥有状态,并通过event的驱动来按照Configurer的配置进行状态变化,同时执行配置中指定的guard、action和listener

2.2 业务逻辑组件:

(具体业务开发在这里写,由框架负责调度)

组件​

处理逻辑类型​

是否阻塞迁移​

Guard

纯校验逻辑 (金额校验/渠道检查)

是,失败则中断迁移

Action

核心业务操作 (支付执行/库存扣减)

是,异常导致迁移失败

Listener

后续操作响应 (通知/日志/监控)

否,异步执行(也可同步)

2.3 流程示例图

3. 示例代码

3.1 依赖引入

org.springframework.statemachinespring-statemachine-starter3.2.0org.springframework.statemachinespring-statemachine-redis1.2.9.RELEASE

3.2 状态枚举定义

public enum OrderStatus { // 待支付,待发货,待收货,已完成 WAIT_PAYMENT(1, \"待支付\"), WAIT_DELIVER(2, \"待发货\"), WAIT_RECEIVE(3, \"待收货\"), FINISH(4, \"已完成\"); private Integer key; private String desc; OrderStatus(Integer key, String desc) { this.key = key; this.desc = desc; } public Integer getKey() { return key; } public String getDesc() { return desc; }}

3.3 事件枚举定义

public enum OrderStatusChangeEvent { // 支付,发货,确认收货 PAYED, DELIVERY, RECEIVED,UNPAY; /** * 获取下一个事件枚举 * * @return 下一个事件枚举 */ public OrderStatusChangeEvent getNextEvent() { switch (this) { case UNPAY: return PAYED; case PAYED: return DELIVERY; case DELIVERY: return RECEIVED; case RECEIVED: // 如果是最后一个事件,则返回null return null; default: // 如果枚举值不在预期范围内,则抛出异常 throw new IllegalArgumentException(\"不支持的事件枚举值\"); } }}

3.4 配置类

@Configuration@EnableStateMachineFactorypublic class OrderStateMachineConfig extends StateMachineConfigurerAdapter { @Autowired private OrderGuard orderGuard; @Autowired private OrderAction orderAction; /** * 配置状态 * * @param states * @throws Exception */ public void configure(StateMachineStateConfigurer states) throws Exception { states .withStates() .initial(OrderStatus.WAIT_PAYMENT) .states(EnumSet.allOf(OrderStatus.class)); } /** * 配置状态转换事件关系 * * @param transitions * @throws Exception */ public void configure(StateMachineTransitionConfigurer transitions) throws Exception { transitions //支付事件:待支付-》待发货 .withExternal() .source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER) .event(OrderStatusChangeEvent.PAYED) .guard(orderGuard) .action(orderAction) .and() //发货事件:待发货-》待收货 .withExternal() .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE) .event(OrderStatusChangeEvent.DELIVERY) .guard(orderGuard) .action(orderAction) .and() //收货事件:待收货-》已完成 .withExternal() .source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH) .event(OrderStatusChangeEvent.RECEIVED) .guard(orderGuard) .action(orderAction) .and() .withExternal() .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_PAYMENT) .event(OrderStatusChangeEvent.UNPAY) .guard(orderGuard) .action(orderAction); }}

3.5 Guard--存放业务检查逻辑

业务开发只用关心实现这个Guard接口不用关心执行调度和状态维护。

@Componentpublic class OrderGuard implements Guard { @Override public boolean evaluate(StateContext context) { Order order = context.getMessage().getHeaders().get(\"order\", Order.class); // ...自定义业务检查逻辑 return true; }}

 3.6 Action---存放业务执行逻辑

业务开发只用关心实现这个Action接口不用关心执行调度和状态维护

@Slf4j@Componentpublic class OrderAction implements Action { @Resource private OrderMapper orderMapper; @Override public void execute(StateContext stateContext) { try { Order order = stateContext.getMessage().getHeaders().get(\"order\", Order.class); State target = stateContext.getTarget(); order.setStatus(target.getId().getKey()); log.info(\"orderAction:{}\", order); // 自定义业务执行逻辑  } catch (Exception e) { log.error(\"订单状态机执行异常\", e); stateContext.getStateMachine().setStateMachineError(new RuntimeException(\"自定义错误\")); throw e; } }}

3.7 核心控制类

对并发有要求的使用工厂方法,每个订单都单独使用一个状态机表达

@Service(\"orderService\")@Slf4jpublic class OrderServiceImpl extends ServiceImpl implements OrderService { @Autowired private StateMachineFactory stateMachineFactory; @Resource private StateMachinePersister stateMachineRedisPersister; @Resource private OrderMapper orderMapper; @Autowired private RedisUtil redisUtil; @Autowired OrderStateListener orderStateListener; /** * 创建订单 * * @param order * @return */ @DS(\"oracle-xxx\") @Transactional(propagation = Propagation.REQUIRES_NEW) public Order create(Order order) { order.setStatus(OrderStatus.WAIT_PAYMENT.getKey()); orderMapper.insert(order); return order; } /** * 对订单进行支付 * * @param id * @return */ @DS(\"oracle-xxx\") @Transactional(propagation = Propagation.REQUIRES_NEW) public boolean pay(Long id) { Order order = orderMapper.selectById(id); log.info(\"线程名称:{},尝试支付,订单号:{}\" ,Thread.currentThread().getName() , id); return autoSendEvent(OrderStatusChangeEvent.PAYED, order); } /** * 发送订单状态转换事件 * synchronized修饰保证这个方法是线程安全的 * * @param changeEvent * @param order * @return */ private boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean result = false; StateMachine orderStateMachine = null; try { // 工厂方法生成状态机 orderStateMachine = stateMachineFactory.getStateMachine(order.getId()); orderStateMachine.addStateListener(orderStateListener); //启动状态机 orderStateMachine.start(); //尝试恢复状态机状态 stateMachineRedisPersister.restore(orderStateMachine, String.valueOf(order.getId())); Message message = MessageBuilder.withPayload(changeEvent).setHeader(\"order\", order).build(); result = orderStateMachine.sendEvent(message); boolean hasError = orderStateMachine.hasStateMachineError(); //持久化状态机状态 if(hasError){ return !hasError; } stateMachineRedisPersister.persist(orderStateMachine, String.valueOf(order.getId())); // 已结束的流程 给key加上过期时间 if (order.getStatus() == OrderStatus.FINISH.getKey()) { redisUtil.set(order.getId(), order.getStatus(), 60 * 60 * 24, TimeUnit.SECONDS); } } catch (Exception e) { log.error(\"订单操作失败:{}\", e); } finally{ if (orderStateMachine != null) { // 释放状态机 orderStateMachine.stop(); } } return result; } private boolean autoSendEvent(OrderStatusChangeEvent changeEvent, Order order) { boolean b = true; while (b && changeEvent != null) { b = sendEvent(changeEvent, order); changeEvent = changeEvent.getNextEvent(); } return b; } 

3.8 监听器  

用来执行一些不影响流程主流程的 日志、通知之类的任务,可异步

@Component@Slf4jpublic class OrderStateListener extends StateMachineListenerAdapter { private StateMachine stateMachine; private Message message; @Override public void stateContext(StateContext context) { StateMachine stateMachine = context.getStateMachine(); this.stateMachine = stateMachine; // 获取当前事件 Message message = context.getMessage(); this.message = message; // 获取状态机 ID String machineId = stateMachine.getId(); // 应用场景:订单状态变更记录 if (context.getStage() == StateContext.Stage.STATE_CHANGED) { OrderStatus oldStatus = context.getSource().getId(); OrderStatus newStatus = context.getTarget().getId(); log.info(\"订单 {} 状态变更: {} → {}\", machineId, oldStatus, newStatus); } if(context.getException()!=null){ log.error(\"状态机异常: {}\",context.getException().getMessage()); } } @DS(\"oracle-xxx\") @Override public void stateChanged(State from, State to) { // 状态变更时触发(如 UNPAID → PAID) System.out.println(\"状态变更: \" + from.getId() + \" → \" + to.getId()); Order order = message.getHeaders().get(\"order\", Order.class); order.setStatus(to.getId().getKey()); } @Override public void stateEntered(State state) { // 进入新状态时触发 System.out.println(\"进入状态: \" + state.getId()); } @Override @Async public void eventNotAccepted(Message message) { // 事件被拒绝时触发(如非法状态转换) System.err.println(\"事件拒绝开始: \" + message.getPayload()); Order order = message.getHeaders().get(\"order\", Order.class); try { Thread.sleep(60000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.err.println(\"事件拒绝结束: \" + message.getPayload()); } @Override @Async public void stateMachineError(StateMachine stateMachine, Exception exception) { // 只能建ring状态机本身在运行中发生的异常,不能处理action抛出的异常 // 可以在此进行重试、告警等操作 log.error(\"错误处理: {}\", exception.getMessage()); } @Override public void stateExited(State state) { // 状态机退出时触发 log.info(\"状态退出: {}\", state.getId()); }}

3.9 持久化

这里直接用的redis持久化,可自己定义成其他持久化方式

@Configuration@Slf4jpublic class Persist { @Resource private RedisConnectionFactory redisConnectionFactory; /** * 持久化到redis中,在分布式系统中使用 * * @return */ @Bean(name = \"stateMachineRedisPersister\") public RedisStateMachinePersister getRedisPersister() { RedisStateMachineContextRepository repository = new RedisStateMachineContextRepository(redisConnectionFactory); RepositoryStateMachinePersist p = new RepositoryStateMachinePersist(repository); return new RedisStateMachinePersister(p); }}

4. 总结

1. 状态转移通过配置类维护,可读性高,新增状态时维护方便。

2. 状态之间转移通过由配置强制指定,不容易出现逻辑错乱。

3. 加锁方便,可以在统一的事件触发入口加redis分布式锁。

4. 业务逻辑处理存放在Guard​、Action​、监听器中,各司其职结构清晰,代码逻辑解耦。