Spring State Machine实例恢复推荐方案及多用户工作流场景适配咨询
Spring State Machine 工作流场景选型方案(v2.4.0 适配)
核心结论
你当前多用户多工作流的场景,优先选择「状态机实例池 + 状态回填 + 持久化」的混合方案,既能避免频繁初始化状态机的性能开销,也能解决单实例复用的阻塞、并发安全问题。
方案1:单工作流对应独立状态机实例(你的初始方案)
优缺点
- 优势:状态完全隔离,无并发冲突,开发逻辑简单,不需要额外处理实例抢占、上下文残留问题
- 劣势:高并发下频繁创建销毁状态机实例会产生明显的性能开销,尤其当状态机定义(状态/事件/拦截器/动作)复杂时,初始化开销会被放大
适配场景:工作流总数量少、并发量低的场景
代码示例
// 状态机基础配置(可根据业务自定义状态、事件枚举) @Configuration @EnableStateMachineFactory public class WorkflowStateMachineConfig extends StateMachineConfigurerAdapter<String, String> { @Override public void configure(StateMachineStateConfigurer<String, String> states) throws Exception { states.withStates() .initial("INIT") .state("STEP1") .state("STEP2") .end("FINISH"); } @Override public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception { transitions.withExternal() .source("INIT").target("STEP1").event("SUBMIT") .and().withExternal() .source("STEP1").target("STEP2").event("AUDIT_PASS") .and().withExternal() .source("STEP2").target("FINISH").event("FINISH_EXEC"); } } // 业务处理逻辑 @Service public class WorkflowService { @Autowired private StateMachineFactory<String, String> stateMachineFactory; @Autowired private StateMachinePersister<String, String, String> persister; // 可自定义绑定Redis/DB做持久化存储 public void processEvent(String workflowId, String event) throws Exception { // 每个工作流请求创建独立实例 StateMachine<String, String> stateMachine = stateMachineFactory.getStateMachine(workflowId); // 从持久化存储恢复当前工作流状态 persister.restore(stateMachine, workflowId); // 执行事件驱动状态流转 stateMachine.sendEvent(event); // 持久化更新后的状态机 persister.persist(stateMachine, workflowId); // 销毁实例释放资源 stateMachine.stop(); } }
方案2:单实例复用+状态回填
优缺点
- 优势:仅一次初始化开销,资源占用极低
- 劣势:状态机本身非线程安全,必须加锁保证串行执行,高并发下会出现严重的请求阻塞,且容易出现上下文残留导致的状态错乱
适配场景:仅单工作流、并发量极低的场景,完全不匹配你的多用户多工作流需求
代码示例
@Service public class SingleInstanceWorkflowService { @Autowired private StateMachine<String, String> singleStateMachine; @Autowired private StateMachinePersister<String, String, String> persister; private final ReentrantLock lock = new ReentrantLock(); public void processEvent(String workflowId, String event) throws Exception { lock.lock(); // 必须加锁,否则并发下状态会直接错乱 try { // 回填当前工作流状态 persister.restore(singleStateMachine, workflowId); singleStateMachine.sendEvent(event); persister.persist(singleStateMachine, workflowId); // 清空上下文,避免残留到下一个工作流请求 singleStateMachine.getStateMachineAccessor().doWithAllRegions(accessor -> { accessor.resetStateMachine(new DefaultStateMachineContext<>(null, null, null, null)); }); } finally { lock.unlock(); } } }
推荐方案:实例池化+状态回填
核心逻辑
通过对象池预初始化一批状态机实例,请求到来时从池中取空闲实例,回填对应工作流的状态后执行事件,执行完成后重置实例上下文并归还到池,既消除了频繁初始化的开销,又保证了并发能力,不存在单实例的阻塞问题。
适配场景:你的多用户多工作流高并发场景
代码示例(依赖commons-pool2实现对象池)
<!-- 引入对象池依赖 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency>
// 状态机实例工厂,用于对象池创建实例 public class StateMachinePooledObjectFactory extends BasePooledObjectFactory<StateMachine<String, String>> { @Autowired private StateMachineFactory<String, String> stateMachineFactory; @Override public StateMachine<String, String> create() throws Exception { StateMachine<String, String> sm = stateMachineFactory.getStateMachine(); sm.start(); return sm; } @Override public PooledObject<StateMachine<String, String>> wrap(StateMachine<String, String> stateMachine) { return new DefaultPooledObject<>(stateMachine); } // 归还实例时自动重置上下文,消除上一个请求的残留数据 @Override public void passivateObject(PooledObject<StateMachine<String, String>> p) throws Exception { StateMachine<String, String> sm = p.getObject(); sm.getStateMachineAccessor().doWithAllRegions(accessor -> { accessor.resetStateMachine(new DefaultStateMachineContext<>(null, null, null, null)); }); } } // 对象池配置 @Configuration public class StateMachinePoolConfig { @Bean public GenericObjectPool<StateMachine<String, String>> stateMachinePool(StateMachinePooledObjectFactory factory) { GenericObjectPoolConfig<StateMachine<String, String>> config = new GenericObjectPoolConfig<>(); config.setMaxTotal(16); // 可根据压测结果调整,一般为CPU核心数的2-4倍 config.setMinIdle(4); config.setMaxWaitMillis(3000); return new GenericObjectPool<>(factory, config); } } // 业务处理逻辑 @Service public class PooledWorkflowService { @Autowired private GenericObjectPool<StateMachine<String, String>> stateMachinePool; @Autowired private StateMachinePersister<String, String, String> persister; public void processEvent(String workflowId, String event) throws Exception { StateMachine<String, String> sm = stateMachinePool.borrowObject(); try { persister.restore(sm, workflowId); sm.sendEvent(event); persister.persist(sm, workflowId); } finally { stateMachinePool.returnObject(sm); } } }
注意事项
- 持久化实现可直接使用SSM 2.4.0自带的
JpaStateMachinePersister或RedisStateMachinePersister,不需要手动实现序列化逻辑 - 实例池大小不需要设置过大,状态机本身执行逻辑很快,16核CPU设置32个实例完全可以支撑每秒数千次的工作流步骤处理请求
内容的提问来源于stack exchange,提问作者Daniel Vilas-Boas
相关产品推荐
相关产品推荐

