Spring Statemachine 状态机详解
作者:csdn_tom_168
SpringStatemachine是Spring应用中的状态机框架,支持复杂状态转换,适用于订单系统等场景,核心概念包括状态、事件、转换,提供守卫、动作、并行处理等高级功能,并支持持久化与可视化,本文给大家介绍Spring Statemachine的相关知识,感兴趣的朋友一起看看吧
Spring Statemachine 详解
Spring Statemachine 是一个强大的状态机框架,用于在 Spring 应用中实现复杂的状态转换逻辑。它特别适合管理具有多种状态和转换的业务流程,如订单系统、工作流引擎、设备控制等。
一、核心概念
1. 状态机基本元素
- 状态(State):系统所处的特定条件
- 事件(Event):触发状态转换的动作
- 转换(Transition):状态之间的迁移
- 守卫(Guard):转换的条件判断
- 动作(Action):状态转换时执行的业务逻辑
2. 状态类型
- 初始状态(Initial State):状态机的起点
- 结束状态(End State):状态机的终点
- 普通状态(Normal State):常规状态
- 选择状态(Choice State):基于条件的分支
- 叉状态(Fork State):并行执行分支
- 连接状态(Join State):合并并行分支
- 历史状态(History State):记录并恢复之前状态
二、依赖配置
Maven 依赖
<dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-core</artifactId> <version>3.2.0</version> </dependency>
Gradle 依赖
implementation 'org.springframework.statemachine:spring-statemachine-core:3.2.0'
三、基础配置
1. 定义状态和事件枚举
public enum States { SI, // 初始状态 S1, S2, SF // 最终状态 } public enum Events { E1, E2 }
2. 配置状态机
@Configuration @EnableStateMachine public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> { @Override public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception { states .withStates() .initial(States.SI) .states(EnumSet.allOf(States.class)) .end(States.SF); } @Override public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception { transitions .withExternal() .source(States.SI) .target(States.S1) .event(Events.E1) .and() .withExternal() .source(States.S1) .target(States.S2) .event(Events.E2); } }
四、高级特性
1. 守卫(Guard)实现条件转换
public class MyGuard implements Guard<States, Events> { @Override public boolean evaluate(StateContext<States, Events> context) { // 检查转换条件 return context.getMessageHeader("key") != null; } } // 在配置中添加守卫 transitions .withExternal() .source(States.S1) .target(States.S2) .event(Events.E2) .guard(new MyGuard());
2. 动作(Action)执行业务逻辑
public class MyAction implements Action<States, Events> { @Override public void execute(StateContext<States, Events> context) { // 执行状态转换时的业务逻辑 System.out.println("Transition action executed"); } } // 在配置中添加动作 transitions .withExternal() .source(States.SI) .target(States.S1) .event(Events.E1) .action(new MyAction());
3. 层次状态(Hierarchical States)
@Override public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception { states .withStates() .initial(States.SI) .state(States.S1) .and() .withStates() .parent(States.S1) .initial(States.S11) .state(States.S12); }
4. 并行状态(Fork/Join)
@Override public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception { states .withStates() .initial(States.SI) .fork(States.SFORK) .join(States.SJOIN) .and() .withStates() .parent(States.SFORK) .initial(States.S1) .end(States.S1END) .and() .withStates() .parent(States.SFORK) .initial(States.S2) .end(States.S2END); } @Override public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception { transitions .withFork() .source(States.SFORK) .target(States.S1) .target(States.S2) .and() .withJoin() .source(States.S1END) .source(States.S2END) .target(States.SJOIN); }
5. 状态机监听器
@Component public class StateMachineListener extends StateMachineListenerAdapter<States, Events> { @Override public void stateChanged(State<States, Events> from, State<States, Events> to) { System.out.println("State changed from " + from + " to " + to); } @Override public void eventNotAccepted(Message<Events> event) { System.err.println("Event not accepted: " + event.getPayload()); } }
五、持久化状态机
1. 配置持久化仓库
@Bean public StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister() { return new JpaStateMachineRuntimePersister<>(); }
2. 启用持久化
@Configuration @EnableStateMachineFactory public class PersistConfig extends StateMachineConfigurerAdapter<States, Events> { @Autowired private StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister; @Override public void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception { config .withPersistence() .runtimePersister(stateMachineRuntimePersister); } }
3. 保存和恢复状态
// 保存状态 stateMachinePersist.persist(stateMachine, "machineId"); // 恢复状态 StateMachine<States, Events> stateMachine = stateMachineFactory.getStateMachine("machineId"); stateMachinePersist.restore(stateMachine, "machineId");
六、状态机可视化
1. 导出UML状态图
UmlStateMachineModelProducer modelProducer = new UmlStateMachineModelProducer(); Model model = modelProducer.produce(stateMachine.getStateMachineModel()); UmlStateMachineModelConverter converter = new UmlStateMachineModelConverter(); String uml = converter.convertToString(model); System.out.println(uml);
2. 生成PlantUML图
@startuml [*] --> SI SI --> S1 : E1 S1 --> S2 : E2 S2 --> SF : E3 SF --> [*] @enduml
七、完整示例:订单状态机
1. 定义状态和事件
public enum OrderStates { CREATED, // 订单创建 PAYMENT_PENDING, // 待支付 PAYMENT_RECEIVED,// 已支付 PROCESSING, // 处理中 SHIPPED, // 已发货 DELIVERED, // 已送达 CANCELLED, // 已取消 RETURNED // 已退货 } public enum OrderEvents { INITIATE_PAYMENT, // 发起支付 PAYMENT_SUCCESS, // 支付成功 PAYMENT_FAILED, // 支付失败 PROCESS_ORDER, // 处理订单 SHIP_ORDER, // 发货 DELIVER_ORDER, // 送达 CANCEL_ORDER, // 取消订单 RETURN_ORDER // 退货 }
2. 配置状态机
@Configuration @EnableStateMachineFactory public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> { @Override public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception { states .withStates() .initial(OrderStates.CREATED) .state(OrderStates.PAYMENT_PENDING) .state(OrderStates.PAYMENT_RECEIVED) .state(OrderStates.PROCESSING) .state(OrderStates.SHIPPED) .state(OrderStates.DELIVERED) .end(OrderStates.CANCELLED) .end(OrderStates.RETURNED); } @Override public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception { transitions // 从创建到待支付 .withExternal() .source(OrderStates.CREATED) .target(OrderStates.PAYMENT_PENDING) .event(OrderEvents.INITIATE_PAYMENT) .and() // 支付成功 .withExternal() .source(OrderStates.PAYMENT_PENDING) .target(OrderStates.PAYMENT_RECEIVED) .event(OrderEvents.PAYMENT_SUCCESS) .and() // 支付失败 .withExternal() .source(OrderStates.PAYMENT_PENDING) .target(OrderStates.CANCELLED) .event(OrderEvents.PAYMENT_FAILED) .and() // 开始处理订单 .withExternal() .source(OrderStates.PAYMENT_RECEIVED) .target(OrderStates.PROCESSING) .event(OrderEvents.PROCESS_ORDER) .and() // 发货 .withExternal() .source(OrderStates.PROCESSING) .target(OrderStates.SHIPPED) .event(OrderEvents.SHIP_ORDER) .and() // 送达 .withExternal() .source(OrderStates.SHIPPED) .target(OrderStates.DELIVERED) .event(OrderEvents.DELIVER_ORDER) .and() // 取消订单(在特定状态下) .withExternal() .source(OrderStates.CREATED) .target(OrderStates.CANCELLED) .event(OrderEvents.CANCEL_ORDER) .and() .withExternal() .source(OrderStates.PAYMENT_PENDING) .target(OrderStates.CANCELLED) .event(OrderEvents.CANCEL_ORDER) .and() // 退货 .withExternal() .source(OrderStates.DELIVERED) .target(OrderStates.RETURNED) .event(OrderEvents.RETURN_ORDER); } }
3. 使用状态机服务
@Service public class OrderService { @Autowired private StateMachineFactory<OrderStates, OrderEvents> factory; private final Map<Long, StateMachine<OrderStates, OrderEvents>> machines = new ConcurrentHashMap<>(); public void createOrder(Long orderId) { StateMachine<OrderStates, OrderEvents> sm = buildStateMachine(orderId); sm.sendEvent(OrderEvents.INITIATE_PAYMENT); } public void processPayment(Long orderId, boolean success) { StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId); if (sm != null) { sm.sendEvent(success ? OrderEvents.PAYMENT_SUCCESS : OrderEvents.PAYMENT_FAILED); } } public void shipOrder(Long orderId) { StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId); if (sm != null && sm.getState().getId() == OrderStates.PROCESSING) { sm.sendEvent(OrderEvents.SHIP_ORDER); } } private StateMachine<OrderStates, OrderEvents> buildStateMachine(Long orderId) { StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine(); sm.start(); machines.put(orderId, sm); return sm; } }
八、最佳实践
1. 状态机设计原则
- 保持状态简单:每个状态应有明确的含义
- 限制状态数量:避免状态爆炸(State Explosion)
- 使用层次状态:管理复杂状态关系
- 合理使用守卫:确保转换条件清晰
- 分离业务逻辑:动作应调用服务而非包含复杂逻辑
2. 性能优化
- 重用状态机实例:避免频繁创建
- 异步事件处理:使用
sendEvent(Message)
异步接口 - 合理持久化:只在必要时持久化状态
- 缓存守卫结果:避免重复计算
3. 错误处理
@Component public class ErrorStateMachineListener extends StateMachineListenerAdapter<OrderStates, OrderEvents> { @Override public void stateMachineError( StateMachine<OrderStates, OrderEvents> stateMachine, Exception exception) { // 记录错误并处理 System.err.println("State machine error: " + exception.getMessage()); stateMachine.stop(); } @Override public void eventNotAccepted(Message<OrderEvents> event) { // 处理不被接受的事件 System.err.println("Event not accepted: " + event.getPayload()); } }
九、测试状态机
JUnit 测试示例
@SpringBootTest public class OrderStateMachineTest { @Autowired private StateMachineFactory<OrderStates, OrderEvents> factory; @Test public void testOrderFlow() { StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine(); sm.start(); // 初始状态应为CREATED assertEquals(OrderStates.CREATED, sm.getState().getId()); // 发起支付 sm.sendEvent(OrderEvents.INITIATE_PAYMENT); assertEquals(OrderStates.PAYMENT_PENDING, sm.getState().getId()); // 支付成功 sm.sendEvent(OrderEvents.PAYMENT_SUCCESS); assertEquals(OrderStates.PAYMENT_RECEIVED, sm.getState().getId()); // 处理订单 sm.sendEvent(OrderEvents.PROCESS_ORDER); assertEquals(OrderStates.PROCESSING, sm.getState().getId()); // 发货 sm.sendEvent(OrderEvents.SHIP_ORDER); assertEquals(OrderStates.SHIPPED, sm.getState().getId()); // 送达 sm.sendEvent(OrderEvents.DELIVER_ORDER); assertEquals(OrderStates.DELIVERED, sm.getState().getId()); } }
十、常见问题解决
1. 事件未被处理
- 检查状态:确保当前状态支持该事件
- 验证守卫:检查守卫条件是否满足
- 查看日志:启用DEBUG日志查看状态机内部处理
2. 状态机不启动
- 检查配置:确保
@EnableStateMachine
或@EnableStateMachineFactory
已启用 - 手动启动:调用
stateMachine.start()
- 验证依赖:确保所有必需依赖已正确配置
3. 并发问题
- 使用同步:对状态机操作加锁
- 消息队列:使用消息队列顺序处理事件
- 状态机池:创建状态机实例池
4. 持久化失败
- 检查序列化:确保状态和事件可序列化
- 数据库配置:验证持久化仓库配置正确
- 事务管理:确保在事务边界内操作状态机
Spring Statemachine 提供了强大的状态管理能力,特别适合处理复杂的业务流程。通过合理设计状态模型、转换规则和业务动作,可以构建出高度可维护和可扩展的状态驱动应用。
到此这篇关于Spring Statemachine 状态机详解的文章就介绍到这了,更多相关Spring Statemachine 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!