当前位置: 首页 > news >正文

状态机——SpringStateMachine嵌套状态流转

SpringStateMachine嵌套状态流转1、问题概述2、定义状态与事件枚举3、配置层级状态节点4、配置层级流转路由 rules5、测试调用与状态打印1、问题概述在 Spring StateMachine 中嵌套状态Substates / Hierarchical States是指在一个父状态Parent State内部包含了一组子状态Child States。这种设计非常适合用来表达“状态中的状态”能够将复杂的业务逻辑按层级进行拆分。在嵌套状态中状态流转遵循一个核心原则如果状态机当前处于某个子状态那么它必然也同时处于该子状态的父状态。假设订单业务中有如下状态PENDING_PAY顶层状态待支付初始状态IN_PAYMENT父状态支付中PAY_PREPARE子状态支付准备中PAY_PROCESSING子状态扣款中PENDING_DELIVER结束状态待发货2、定义状态与事件枚举//订单状态枚举publicenumOrderState{PENDING_PAY,// 顶层状态待支付初始状态IN_PAYMENT,// 父状态支付中// 以下为 IN_PAYMENT 的内部子状态PAY_PREPARE,// 子状态支付准备中PAY_PROCESSING,// 子状态扣款中PENDING_DELIVER// 结束状态待发货}//订单事件枚举publicenumOrderEvent{GO_PAY,// 外部事件去支付待支付 - 支付中BANK_CONNECT,// 内部事件连接渠道支付准备中 - 扣款中PAY_SUCCESS,// 业务结果事件扣款成功从扣款中跳出 - 待发货PAY_FAIL// 业务结果事件扣款失败从扣款中跳出 - 回到待支付}3、配置层级状态节点在 configure(StateMachineStateConfigurer) 中我们利用 .parent() 语法来编织状态之间的树状层级关系。ConfigurationEnableStateMachineFactory(namepaymentStateMachineFactory)publicclassPaymentStateMachineConfigextendsEnumStateMachineConfigurerAdapterOrderState,OrderEvent{Overridepublicvoidconfigure(StateMachineStateConfigurerOrderState,OrderEventstates)throwsException{states.withStates()//注册最外层的顶层独立状态.initial(OrderState.PENDING_PAY)//顶层起点待支付.end(OrderState.PENDING_DELIVER)//顶层终点待发货.state(OrderState.IN_PAYMENT)//宏观负状态支付中.and()//嵌套子状态.withStates().parent(OrderState.IN_PAYMENT)//指明父节点.initial(OrderState.PAY_PREPARE)//子状态的第一个状态.state(OrderState.PAY_PROCESSING);//扣款中}}4、配置层级流转路由 rules在配置流转时Spring StateMachine 的嵌套路由支持两种经典的流转模式外部流转withExternal导致状态发生宏观层级跨越的跳转比如跳入/跳出父状态。局部流转withLocal在父状态的树内部进行安全的子状态切换不会触发父状态的 onExit 或 onEntry 动作。Overridepublicvoidconfigure(StateMachineTransitionConfigurerOrderState,OrderEventtransitions)throwsException{transitions// 1. 待支付 - 跳入父状态支付中// 此时状态机激活集合变为[IN_PAYMENT, PAY_PREPARE].withExternal().source(OrderState.PENDING_PAY).target(OrderState.IN_PAYMENT).event(OrderEvent.GO_PAY).and()// 2. 父状态内部流转支付准备中 - 扣款中// 此时状态机激活集合变为[IN_PAYMENT, PAY_PROCESSING].withExternal().source(OrderState.PAY_PREPARE).target(OrderState.PAY_PROCESSING).event(OrderEvent.BANK_CONNECT).and()// 3. 【核心流转一】扣款成功打破父状态流转到顶层的“待发货”// 状态机将彻底销毁内部的所有子状态指针.withExternal().source(OrderState.IN_PAYMENT).target(OrderState.PENDING_DELIVER).event(OrderEvent.PAY_SUCCESS).and()// 4. 【核心流转二】扣款失败打破父状态无条件滚回到顶层的“待支付”// 状态机同样会销毁内部指针让订单恢复到最初可以重新发起支付的状态.withExternal().source(OrderState.IN_PAYMENT).target(OrderState.PENDING_PAY).event(OrderEvent.PAY_FAIL);}5、测试调用与状态打印我们在测试中连续投递事件看看状态机的内存激活状态集合sm.getState().getIds()是如何展现嵌套层次的。publicvoidtestHierarchicalStates(){StateMachineOrderState,OrderEventsmfactory.getStateMachine(order_999);sm.startReactively().block();System.out.println(--- 1. 初始化 ---);System.out.println(当前激活状态: sm.getState().getIds());// [PENDING_ORDER]// 2. 去支付 - 激活嵌套sm.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.GO_PAY).build())).blockLast();System.out.println(--- 2. 发送 GO_PAY 后 ---);System.out.println(当前激活状态: sm.getState().getIds());// 预期输出: [IN_PAYMENT, PAY_PREPARE] (父子同时激活)// 3. 连接银行 - 子状态流转sm.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.BANK_CONNECT).build())).blockLast();System.out.println(--- 3. 发送 BANK_CONNECT 后 ---);System.out.println(当前激活状态: sm.getState().getIds());// 预期输出: [IN_PAYMENT, PAY_PROCESSING] (父状态不变子状态向前)// 4. 支付成功 - 强行打破嵌套融合成顶层终态sm.sendEvent(Mono.just(MessageBuilder.withPayload(OrderEvent.PAY_SUCCESS).build())).blockLast();System.out.println(--- 4. 发送 PAY_SUCCESS 后 ---);System.out.println(当前激活状态: sm.getState().getIds());// 预期输出: [PENDING_DELIVER] (子状态全部销毁回归单顶层状态)}--- 初始状态 --- [PENDING_PAY] --- 1. 点击去支付后 --- [IN_PAYMENT, PAY_PREPARE] --- 2. 进入银行扣款中后 --- [IN_PAYMENT, PAY_PROCESSING] --- 3. 收到扣款失败回调后 --- [PENDING_PAY] --- 4. 第二次尝试重新进入扣款中 --- [IN_PAYMENT, PAY_PROCESSING] --- 5. 收到扣款成功回调后 --- [PENDING_DELIVER]
http://www.zskr.cn/news/1341269.html

相关文章:

  • 终极GTA5游戏助手:YimMenu完整实战指南
  • Postgresql基础实践教程(二)
  • 利用Taotoken审计日志功能追踪与分析团队内部的模型使用情况
  • 单日大涨4.52%!华泰柏瑞中韩半导体ETF(513310.SH)上演“高热度”行情,溢价率风险引关注
  • 2026降AI工具怎么选?4款主流工具实测,轻松把AI率压到20%内
  • 从elm-react-native学习React Native最佳实践:10个关键开发技巧
  • 极物科技 正点原子 RK3588 部署 Qwen2-VL Qwen2-VL-2B-Instruct,提供模型和npu驱动0.9.8的kernel
  • (C语言)指针详解与应用
  • 软工作业4
  • CANN/asc-devkit浮点ilogbf函数文档
  • weather_landscape性能优化技巧:提升图像生成速度和资源利用效率
  • 实习准备(26_05_21)
  • # 2026年西安中考复读学校谁家靠谱?教学、案例与管理模式横向测评 - 科技焦点
  • Kubepug快速入门:5分钟学会Kubernetes集群升级安全检查
  • 蓝晒法AI化转型关键突破,仅限前200名领取:含47个已验证蓝晒LUT预设+光照角度黄金比例表
  • 终极指南:如何彻底解决PHP Intelephense常见问题:索引失败、内存溢出、补全失效
  • mob源码深度解析:Go语言实现高效Git协作工具的架构奥秘
  • 3个真实开发场景:Continue如何让你的JetBrains IDE变成AI编程伙伴
  • 得电
  • 在Linux服务器上装了个国产AI代码助手,怎么让团队其他人也能用上
  • 建筑数据驱动预测控制方法应用【附模型】
  • mob高级用法:自定义分支命名和计时器集成
  • 什么是换根DP及第一步操作说明
  • ROCm rocr-libhsakmt分析系列3: aperture概念
  • mpv.net:Windows平台最强大的开源媒体播放器解决方案
  • CodeXGLUE代码摘要生成实战:让AI为你的代码自动写注释
  • 希腊语语音合成“听不出是AI”?20年语音专家私藏的5步Prosody微调法(含ElevenLabs CLI命令集+基频曲线校正图谱)
  • OpenELB与K3s集成:边缘计算场景下的终极负载均衡解决方案指南 [特殊字符]
  • pointer reference作为顶层参数(三)
  • Array作为顶层参数-优化设计(二)