Spring State Machine 基于条件变更状态的正确实现方式咨询
核心问题分析
- 逻辑执行时机错误
你当前写的packageAction()方法是在创建Action实例的时候判断packed变量的值,而非Action实际被状态机调用执行时动态判断。方法返回的lambda表达式里才是过渡触发时真正会执行的逻辑,你把业务判断写到了lambda外面,逻辑自然不会按预期触发。 - 未绑定Action到过渡规则
你只定义了Action方法,没有在过渡配置中将它和NEW到PACKAGED的过渡关联,状态机触发对应过渡时根本不会执行这段逻辑。
修复方案
1. 修正Action逻辑
把打包业务判断和事件发送都放到lambda内部,保证每次过渡触发时都会动态执行:
public Action<States, Events> packageAction() { return context -> { // 此处为过渡触发时实际执行的打包业务逻辑 boolean packed = executePackagingBusiness(); // 发送事件后可以判断返回值确认是否发送成功,避免状态机未就绪导致事件丢失 if(packed){ context.getStateMachine().sendEvent(Events.process); }else{ context.getStateMachine().sendEvent(Events.error); } }; }
2. 绑定Action到过渡配置
修改你的过渡配置代码,给NEW到PACKAGED的过渡添加action绑定:
@Override public void configure(final StateMachineTransitionConfigurer<States, Events> transitions) throws Exception { transitions .withExternal() .source(States.NEW).target(States.PACKAGED).event(Events.pack) .action(packageAction()) // 新增这行绑定打包逻辑 .and() // 剩余原有过渡规则保持不变即可 .withExternal() .source(States.PACKAGED).target(States.PROCESS).event(Events.process) .and() .withExternal() .source(States.PACKAGED).target(States.ERROR).event(Events.error) .and() .withExternal() .source(States.PROCESS).target(States.DELIVER).event(Events.deliver) .and() .withExternal() .source(States.PROCESS).target(States.ERROR).event(Events.error); }
更符合状态机规范的优化方案
你也可以不用在Action里主动发事件,改用状态机原生的Guard(守卫)实现条件分支,逻辑更清晰也更符合状态机的设计理念:
- 定义守卫判断逻辑
// 打包成功守卫 public Guard<States, Events> packSuccessGuard() { return context -> { boolean packed = executePackagingBusiness(); // 可以将打包结果存入扩展状态供后续逻辑使用 context.getExtendedState().getVariables().put("packSuccess", packed); return packed; }; } // 打包失败守卫 public Guard<States, Events> packFailGuard() { return context -> !Boolean.TRUE.equals(context.getExtendedState().getVariables().get("packSuccess")); }
- 调整过渡配置添加守卫
.transitions .withExternal() .source(States.NEW).target(States.PACKAGED).event(Events.pack) .and() .withExternal() .source(States.PACKAGED).target(States.PROCESS).event(Events.process) .guard(packSuccessGuard()) .and() .withExternal() .source(States.PACKAGED).target(States.ERROR).event(Events.error) .guard(packFailGuard()) // 剩余其他过渡规则保持不变
内容的提问来源于stack exchange,提问作者pranay jain
相关产品推荐
相关产品推荐

