SpringBoot状态机

Spring Boot 状态机(State Machine)是 Spring Framework 提供的一种用于实现复杂业务逻辑的状态管理工具。它基于有限状态机(Finite State Machine, FSM)的概念,允许开发者定义一组状态、事件以及它们之间的转换规则。这在处理具有多个步骤或条件的工作流时特别有用。

Spring StateMachine 组件

Spring StateMachine 是一个专门设计来帮助构建和管理状态机的库。它提供了丰富的功能来简化状态机的配置和使用。以下是几个关键概念:

  • 状态(States):表示系统可以处于的不同状况。
  • 事件(Events):触发从一个状态到另一个状态的转换。
  • 转换(Transitions):定义了在特定事件发生时如何从一个状态转移到另一个状态。
  • 动作(Actions):当进入某个状态或执行某些转换时可以执行的操作。
  • 守卫(Guards):条件检查器,用于确定是否允许特定转换发生。

如下图示例:有限的状态集是“opend”以及“closed”。如果“现态”是“opend”,当“条件”为“Close”时,执行的“动作”是“close door”,次态则为“closed”。状态机逻辑执行完毕后“closed”则变成了“现态”。

应用场景

Spring 状态机(Spring State Machine)作为一种强大的状态管理和转换工具,在多个领域有着广泛的应用场景。以下是几个典型示例的详细解释:

1. 订单生命周期管理

在电商应用中,订单状态可能经历创建、支付、发货、确认收货直至完成或取消等多个状态变化。通过 Spring State Machine,你可以清晰地定义并控制这些状态之间的合法转换过程。例如:

  • 创建订单:当用户提交订单时,状态机从初始状态 CREATED 开始。
  • 支付订单:一旦支付成功,状态机接收事件 PAYMENT_RECEIVED,从而将订单状态转移到 PAID
  • 发货:仓库系统接收到发货指令后,状态机会根据事件 SHIP_ORDER 将订单状态转移到 SHIPPED
  • 确认收货:买家确认收货后,状态机接收 DELIVERED 事件,订单进入 COMPLETED 状态。
  • 取消订单:如果在任意步骤出现问题,可以通过 CANCEL_ORDER 事件将订单状态转移到 CANCELED

同时,在每个状态变迁时,可以触发相应的操作,如发送邮件通知、更新库存等。

2. 工作流引擎

在企业级应用中,诸如请假审批流程、报销流程等工作流通常具有多个步骤和决策点。状态机可以用来描述每个步骤之间的关系及转换条件,确保流程按照预设规则进行。例如:

  • 发起申请:员工提交请假申请,状态机从 DRAFT 转移到 SUBMITTED
  • 主管审批:主管批准或拒绝申请,状态机根据结果转移到 APPROVED 或 REJECTED
  • HR 复核:对于特定类型的请假,可能需要 HR 进行复核,状态机进一步转移到 HR_REVIEW
  • 最终确定:所有审批完成后,状态机最终转移到 CONFIRMED 或直接结束流程。

3. 游戏逻辑

在游戏开发中,游戏角色、游戏关卡、战斗场景等都有各自的状态。状态机可用于实现角色的不同行动模式切换、关卡过关条件判断、战斗状态循环等复杂逻辑。例如:

  • 角色状态:玩家角色可以在 IDLEMOVINGATTACKINGDEFENDING 等状态之间切换,每种状态对应不同的行为模式。
  • 关卡状态:关卡可以从 START 到 PLAYING 再到 COMPLETED 或 FAILED,并且可以根据玩家的表现动态调整难度。
  • 战斗状态:战斗场景中的状态机可以管理回合制战斗中的 PLAYER_TURN 和 ENEMY_TURN,以及处理 VICTORY 或 DEFEAT 结果。

4. 设备状态监控

在物联网(IoT)应用中,对设备运行状态进行实时跟踪和管理时,可以根据设备接收到的各种信号或指令触发状态转变。例如:

  • 开机/待机/运行:设备根据电源开关、用户交互或其他传感器数据在 POWER_ONSTANDBY 和 RUNNING 状态间切换。
  • 故障检测:设备检测到异常情况时,状态机会转移到 ERROR 状态,并触发报警机制。
  • 维修状态:设备进入维修模式后,状态机保持在 MAINTENANCE 状态直到修复完成。

订单流程扭转简单示例

pom.xml 添加依赖

        <dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-starter</artifactId><version>4.0.0</version></dependency>

订单模型

这里方便演示,其他的字段根据需要自行添加

package com.coderlk.state.model;import com.coderlk.state.config.OrderStatus;
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Order {private OrderStatus status;}

订单状态

package com.coderlk.state.config;/*** 订单状态*/
public enum OrderStatus {//待支付,待发货,待收货,订单结束INIT , PAYED, WAIT_DELIVERY, RECEIVED;
}

订单状态改变事件

package com.coderlk.state.config;/*** 订单状态改变事件*/
public enum OrderEvents {//支付,发货,确认收货PAY, DELIVERY, RECEIVE;
}

 配置状态机

package com.coderlk.state.config;import com.coderlk.state.model.Order;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.StateMachineContext;
import org.springframework.statemachine.StateMachinePersist;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.persist.DefaultStateMachinePersister;
import org.springframework.statemachine.support.DefaultStateMachineContext;import java.util.EnumSet;/*** 订单状态机配置*/
@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderEvents> {/*** 配置状态** @param states* @throws Exception*/public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvents> states) throws Exception {states.withStates().initial(OrderStatus.INIT).states(EnumSet.allOf(OrderStatus.class));}/*** 配置状态转换事件关系** @param transitions* @throws Exception*/public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvents> transitions) throws Exception {transitions.withExternal().source(OrderStatus.INIT).target(OrderStatus.PAYED).event(OrderEvents.PAY).and().withExternal().source(OrderStatus.PAYED).target(OrderStatus.WAIT_DELIVERY).event(OrderEvents.DELIVERY).and().withExternal().source(OrderStatus.WAIT_DELIVERY).target(OrderStatus.RECEIVED).event(OrderEvents.RECEIVE);}/*** 持久化配置* 在实际使用中,可以配合Redis等进行持久化操作** @return*/@Beanpublic DefaultStateMachinePersister<Object,Object,Order> persister() {return new DefaultStateMachinePersister<>(new StateMachinePersist<>() {@Overridepublic void write(StateMachineContext<Object, Object> context, Order order) throws Exception {//todo 持久化处理}@Overridepublic StateMachineContext<Object, Object> read(Order order) throws Exception {//此处直接获取Order中的状态,其实并没有进行持久化读取操作return new DefaultStateMachineContext<>(order.getStatus(), null, null, null);}});}
}

处理事件

package com.coderlk.state.service;import com.coderlk.state.config.OrderStatus;
import com.coderlk.state.config.OrderEvents;
import com.coderlk.state.model.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;
import org.springframework.stereotype.Component;@Component("orderStateListener")
@Slf4j
@WithStateMachine(name = "orderStateMachine")
public class OrderStateListener {@OnTransition( source = "INIT" ,target = "PAYED")public boolean pay(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");order.setStatus(OrderStatus.PAYED);log.info("订单表保存数据");log.info("发送站内消息");log.info("回调支付接口");log.info("同步至数据仓库");return true;}@OnTransition( source = "PAYED" , target = "WAIT_DELIVERY")public boolean delivery(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");order.setStatus(OrderStatus.WAIT_DELIVERY);log.info("创建物流订单");log.info("更新物流订单状态");log.info("同步至数据仓库");return true;}@OnTransition(source = "SHIPPED" , target = "RECEIVED")public boolean receive(Message<OrderEvents> message){Order order = (Order) message.getHeaders().get("order");order.setStatus(OrderStatus.PAYED);log.info("更新订单数据");log.info("同步至数据仓库");return true;}
}
package com.coderlk.state.service;import com.coderlk.state.config.OrderStatus;
import com.coderlk.state.config.OrderEvents;
import com.coderlk.state.model.Order;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Component;@Component("orderProcessor")
@Slf4j
public class OrderProcessor {@Resourceprivate StateMachine<OrderStatus, OrderEvents> orderStateMachine;@Resourceprivate StateMachinePersister<OrderStatus, OrderEvents, Order> persister;public  Boolean process(Order order, OrderEvents event){Message<OrderEvents> message = MessageBuilder.withPayload(event).setHeader("order", order).build();boolean b = sendEvent(message);return b;}@SneakyThrowsprivate boolean sendEvent(Message<OrderEvents> message) {Order order = (Order) message.getHeaders().get("order");persister.restore(orderStateMachine, order);boolean result = orderStateMachine.sendEvent(message);return result;}
}

启动

package com.coderlk.state;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StateMachineApplication {public static void main(String[] args) {SpringApplication.run(StateMachineApplication.class, args);}}

测试

支付流程

2024-12-24T15:26:19.088+08:00  INFO 44471 --- [           main] c.c.state.service.OrderStateListener     : 订单表保存数据
2024-12-24T15:26:19.088+08:00  INFO 44471 --- [           main] c.c.state.service.OrderStateListener     : 发送站内消息
2024-12-24T15:26:19.088+08:00  INFO 44471 --- [           main] c.c.state.service.OrderStateListener     : 回调支付接口
2024-12-24T15:26:19.089+08:00  INFO 44471 --- [           main] c.c.state.service.OrderStateListener     : 同步至数据仓库

如果读者对其他流程感兴趣,可以自行测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/890571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于图注意力网络的两阶段图匹配点云配准方法

Two-stage graph matching point cloud registration method based on graph attention network— 基于图注意力网络的两阶段图匹配点云配准方法 从两阶段点云配准方法中找一些图匹配的一些灵感。文章提出了两阶段图匹配点云配准网络&#xff08;TSGM-Net&#xff09; TSGM-Ne…

uniapp跨平台开发---webview调用app方法

1.app端实现 注意:为了实现实时通信,app端页面是.nvue 代码实现 <template><view class"content"><view class"web-view"><web-view class"web-view" :src"url" ref"webview" onPostMessage"o…

【专题】2024年悦己生活消费洞察报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p38654 在当今时代背景下&#xff0c;社会发展日新月异&#xff0c;人们的生活方式与消费观念正经历深刻变革。MoonFox 月狐数据的《2024 年悦己生活消费洞察报告》聚焦于这一充满活力与变化的消费领域。随着就业、婚姻等社会压力的…

生产看板管理系统涵盖哪些方面

嘿&#xff0c;各位搞生产管理的朋友&#xff0c;肯定都碰到过些麻烦事儿吧。我就寻思着&#xff0c;能不能弄出个 “明明白白” 的工作场地呢&#xff1f;让员工和管理人员都能随时查查生产进度&#xff0c;一发现生产里有啥问题就能立马知道。 生产进度不好追踪生产过程不清…

密码学期末考试笔记

文章目录 公钥加密之前的部分 (非重点&#xff0c;关注工具怎么用&#xff0c;和性质)一、对称加密 (symmetric ciphers)1. 定义 二、PRG (伪随机数生成器)1. 定义2. 属性 三、语义安全 (Semantic Security)1. one-time key2. 流密码是语义安全的 四、分组密码 (Block Cipher)1…

workman服务端开发模式-应用开发-vue-element-admin挂载websocket

一、项目根目录main.js添加全局引入 import /utils/websocket 二、在根目录app.vue 中初始化WebSocket连接 <template><div id"app"><router-view /></div> </template><script>import store from ./store export default {n…

我的 2024 年终总结

2024 年&#xff0c;我离开了待了两年的互联网公司&#xff0c;来到了一家聚焦教育机器人和激光切割机的公司&#xff0c;没错&#xff0c;是一家硬件公司&#xff0c;从未接触过的领域&#xff0c;但这还不是我今年最重要的里程碑事件 5 月份的时候&#xff0c;正式提出了离职…

信创源代码加密的答案:信创沙箱

在信息化与工业化融合创新&#xff08;信创&#xff09;的背景下&#xff0c;企业面临着前所未有的数据安全挑战。SDC沙盒技术以其独特的隔离和保护机制&#xff0c;为信创环境提供了强有力的支持。以下是SDC沙盒在信创支持方面的优势&#xff0c;这些优势体现了其在保护企业数…

Leecode刷题C语言之根据第k场考试的分数排序

执行结果:通过 执行用时和内存消耗如下&#xff1a; int gk 0;int compare(const void* a, const void* b) {int* ua *(int**)a;int* ub *(int**)b;return ub[gk] - ua[gk]; }int** sortTheStudents(int** score, int scoreSize, int* scoreColSize, int k, int* returnSiz…

Linux 下SVN新手操作手册

下面来介绍Linux 下 SVN操作方法&#xff1a; 1、SVN的安装 Centos 7 安装Subversion sudo yum -y install subversion Ubuntu 安装Subversion sudo apt-get install subversion 自定义安装&#xff0c;官方地址&#xff1a;https://subversion.apache.org/ 2、SVN的使用…

ArcGIS Pro 3.4新功能3:空间统计新特性,基于森林和增强分类与回归,过滤空间自相关

目录 应用 1&#xff1a;它是相关性还是托布勒第一定律&#xff1f; 应用 2&#xff1a;将空间带入非空间模型 结论 在 ArcGIS Pro 3.4 中&#xff0c;我们在新的空间组件实用程序&#xff08;Moran 特征向量&#xff09;工具集中发布了一个新工具 - 从字段过滤空间自相关。…

自定义一个maven骨架 | 最佳实践

自定义一个maven骨架 | 最佳实践 目的&#xff1a;将一个多模块项目的基础结构制作成maven骨架&#xff0c;实现项目的快速构建&#xff0c;风格统一 公司内部会制定自己的规范及包结构。当创建新项目的时候就需要选择骨架&#xff0c;即可生成包结构。 Archetype都为不同类型的…

CTFHUB-web进阶(Bypassdisable_function)

LD_PRELOAD 来到首页发现有一句话直接就可以用蚁剑连接 根目录里有/flag但是不能看;命令也被ban了就需要绕过了 绕过工具在插件市场就可以下载 如果进不去的话 项目地址: #本地仓库;插件存放 antSword\antData\plugins 绕过选择 上传后我们点进去可以看到多了一个绕过的文件;…

workman服务端开发模式-GatewayWorker的使用

一、GatewayWorker介绍 Workerman是一个使用PHP开发的高性能组件&#xff0c;用于构建高性能的异步并发TCP、UDP、Unix Socket、HTTP、Websocket服务。 GatewayWorker是基于Workerman开发的一套TCP长连接的应用框架&#xff0c;实现了单发、群发、广播等接口&#xff0c;内置了…

oracle linux8.10+ oracle 23ai安装

介质准备&#xff1a; 数据库23ai https://edelivery.oracle.com 上述网站下载基础版本&#xff0c;本次未使用。 本次是安装了带补丁的版本&#xff1a; Database Release Update 23.6.0.24.10 GoldImage表示带补丁用于直接安装的软件包 查找888.1对应Primary Note for …

《软件设计的哲学》阅读摘要之设计原则

《软件设计的哲学》&#xff08;A Philosophy of Software Design&#xff09;是一本在软件架构与设计领域颇具影响力的书籍&#xff0c;作者 John Ousterhout 在书中分享了诸多深刻且实用的软件设计理念。书中列举的这些设计原则&#xff0c;汇聚了作者丰富的实战经验与深邃的…

uniApp打包H5发布到服务器(docker)

使用docker部署uniApp打包后的H5项目记录&#xff0c;好像和VUE项目打包没什么区别... 用HX打开项目&#xff0c;首先调整manifest.json文件 开始用HX打包 填服务器域名和端口号~ 打包完成后可以看到控制台信息 我们可以在web文件夹下拿到下面打包好的静态文件 用FinalShell或…

项目实战——高并发内存池

一.项目介绍 本项目——高并发内存池&#xff0c;是通过学习并模仿简化 google 的一个开源项目 tcmalloc &#xff0c;全称 Thread-Caching Malloc&#xff0c;即线程缓存的malloc&#xff0c;模拟实现了一个自己的高并发内存池&#xff0c;用于高效的多线程内存管理&#xff…

Apache Log4j漏洞复现

所用环境 宝塔云服务器 log4j2 是Apache的⼀个java日志框架&#xff0c;我们借助它进行日志相关操作管理&#xff0c;然而在2021年末log4j2爆出了远程代码执行漏洞&#xff0c;属于严重等级的漏洞。 apache log4j通过定义每⼀条日志信息的级别能够更加细致地控制日志⽣成地过…

自动驾驶控制算法-横向误差微分方程LQR前馈控制

本文是学习自动驾驶控制算法第六讲 前馈控制与航向误差以及前两节的学习笔记。 1 横向误差微分方程 以规划的轨迹作为自然坐标系&#xff0c;计算自车在轨迹上的投影点&#xff0c;进而计算误差&#xff1a; 如图所示&#xff0c;横向误差为 d d d&#xff0c;航向误差为 θ…