Spring State Machine多初始状态与并发执行支持技术问询
Spring State Machine 集成疑问解答
背景
我们近期已将Spring State Machine集成至工作流,具体使用方式为:从SQS队列接收事件,通过状态机处理;完成状态转换后将事件推回SQS队列持久化,每个事件对应初始化一次状态机并执行转换。
疑问
- 是否支持从多个初始状态启动,执行至推送事件到SQS队列后暂停,即支持部分执行,而非必须按顺序走完所有阶段?
- 当前状态机似乎只能单事件处理,能否通过每次触发事件时创建新实例实现多事件并发处理?
状态机配置代码
状态与初始状态配置
public void configure(StateMachineStateConfigurer<RedactionStates, RedactionEvents> states) throws Exception { states.withStates() .initial(RedactionStates.S1) // default initial state .state(RedactionStates.S2) .state(RedactionStates.S3) .state(RedactionStates.S4) .end(RedactionStates.S5); }
转换配置
public void configure( StateMachineTransitionConfigurer<RedactionStates, RedactionEvents> transitions) throws Exception { transitions .withInternal() .source(RedactionStates.S1) .event(RedactionEvents.E1) .and() .withExternal() .source(RedactionStates.S1) .target(RedactionStates.S2) .event(RedactionEvents.E2) }
解答
1. 多初始状态与部分执行支持
Spring State Machine完全支持这两个需求:
- 多初始状态配置:在状态配置中,可以通过多次调用
.initial()方法指定多个初始状态,例如:
也可以通过传入状态集合的方式批量指定。states.withStates() .initial(RedactionStates.S1) .initial(RedactionStates.S2) // 其他状态配置... - 部分执行/暂停:你的场景本身就适合实现“暂停”逻辑——每次处理事件时,从SQS消息中读取当前事件对应的状态,初始化状态机到该状态(而非默认初始状态),处理完当前转换后推回SQS,随后销毁状态机实例。下次接收该事件时,重复此流程即可继续执行。
重置状态机到指定状态的核心代码示例:// 从SQS消息中获取当前状态,比如currentState StateMachine<RedactionStates, RedactionEvents> stateMachine = stateMachineFactory.getStateMachine(); stateMachine.getStateMachineAccessor().doWithAllRegions(sma -> { sma.resetState(StateMachineState.of(currentState)); }); // 触发对应事件 stateMachine.sendEvent(eventFromSQS);
2. 多事件并发处理实现
完全可以通过为每个事件创建独立状态机实例实现多事件并发处理:
Spring State Machine实例是轻量级的,且每个实例的状态相互隔离。你可以通过StateMachineFactory为每个待处理事件创建新实例,示例代码如下:
@Autowired private StateMachineFactory<RedactionStates, RedactionEvents> stateMachineFactory; // 处理单个事件的逻辑 public void processEvent(RedactionEvents event, RedactionStates currentState) { // 创建新的状态机实例 StateMachine<RedactionStates, RedactionEvents> stateMachine = stateMachineFactory.getStateMachine(); // 重置到当前事件对应的状态(如果不是默认初始状态) stateMachine.getStateMachineAccessor().doWithAllRegions(sma -> { sma.resetState(StateMachineState.of(currentState)); }); // 触发事件 stateMachine.sendEvent(event); // 处理完成后,状态机实例可被GC回收,无需手动销毁 }
配合多线程的SQS消费者(例如使用线程池处理消息),就能实现多个事件的并行处理,各实例之间不会互相干扰。
内容的提问来源于stack exchange,提问作者Jaspreet Chhabra
相关产品推荐
相关产品推荐

