Spring Statemachine应用实践( 四 )

注意事项

  • 由于框架中每次都是加载一个状态机内存实例,所以在执行状态转移相关代码时一定要加分布式锁!!!建议状态维护提供统一调用service,开启事务、处理异常 。
  • spring-statemachine异常包装比较另类,如guard、action以及listener中发生异常,状态机会捕获并把异常信息捕获为警告,状态也能够成功转移到次态,这显然不符合 我们的需求,所以调用后需要手动判断是否发生异常stateMachine.hasStateMachineError(),但statemachine并没有给提供获取异常信息的接口,所以在guard 和action中将异常信息用变量的方式解决此问题,stateMachine.getExtendedState().getVariables().put("message", "当前状态不满足执行条件");
  • @EnableStateMachineFactory开启工厂模式,然后通过StateMachineService从持久化层加载一个状态机实例 。
  • 当一个project中有多个业务状态机时,@EnableStateMachineFactory(name = "xxx")为工厂配置名称以区别不同的业务状态机 。
  • 当使用withChoice()时,一定要在配置StateMachineStateConfigurer.choice()配置分支状态,否则将不生效 。
扩展-与squirrel-foundation异同@Componentpublic class ActivityMachine extends SquirrelStateMachine<ActivityMachine, State, Event, TransmitCmd> {private final ActivityStateService activityStateService;public ActivityMachine(ApplicationContext applicationContext) {super(applicationContext);activityStateService = applicationContext.getBean(ActivityStateService.class);}@Overridepublic void buildStateMachine(StateMachineBuilder<ActivityMachine, State, Event, TransmitCmd> stateMachineBuilder) {stateMachineBuilder.externalTransition().from(State.INIT).to(State.DRAFT).on(Event.SAVE).when(applicationContext.getBean(SubmitCondition.class));//以下省略,大致与spring-statemachine相同}@Overridepublic ActivityMachine createStateMachine(State stateId) {ActivityMachine activityMachine = super.createStateMachine(stateId);activityMachine.addStartListener(new StartListener<ActivityMachine, State, Event, TransmitCmd>() {});return activityMachine;}@Overrideprotected void afterTransitionDeclined(S fromState, E event, C context) {//转移状态未执行}@Overrideprotected void afterTransitionCausedException(S fromState, S toState, E event, C context) {// 转移状态时发生异常}@Overrideprotected void afterTransitionCompleted(State fromState, State toState, Event event, TransmitCmd context) {log.info("from {} to {} on {}, {}", fromState.getDesc(), toState.getDesc(), event.getDesc(), context);}}说明:
  • squirrel-foundation直接可继承AbstractStateMachine实例化状态机,配置上大体相同只是使用的是from、to、on、when词不同,框架builder的约束太强 。
  • 不支持choice分支状态 。
  • 状态机异常处理afterTransitionCausedException相比spring-statemachine更加方便、易用 。
  • 状态的持久化通过重写afterTransitionCompleted方法即可 。
5.使用后的效果如何?以下是在开发和迭代维护期间,真切体会到状态机带来好处的两个小场景 。
  • 由于新项目中涉及到跨部门卡券业务,在开发初期审核活动通过时同步创建卡券批次,却忽略了异步生成券码的时间,随着开发的深入才意识到此问题 。此时只需要在状态审核通过时加一个过渡状态并启动一个任务去轮询券码是否创建完成即可,丝毫不影响已开发的代码 。
  • 最初的需求设计时,活动下线后是不能再次上线的,在需求迭代期内又增加了再次上线的功能,状态机流转逻辑清晰,只需要再增加个状态配置流转事件就行,就为状态机赋予了再次上线的能力 。
6.总结 在实践的过程中,在spring-statemachine官方文档结合google摸索使用的过程中,遇到持久化存储StateMachineContext、异常处理,以及状态分支等问题 。目前回头看来也不复杂,如今写出来总结一下,希望对小伙伴们有所帮助 。
最后建议在状态流程不是很复杂的情况,如果您也厌烦了if...else,那么不妨尝试一下squirrel-foundation,相信也是不错的选择 。
参考文献
  1. ??https://baike.baidu.com/item/%E7%8A%B6%E6%80%81%E6%9C%BA/6548513?fr=aladdin??
  2. ??https://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA??


    推荐阅读