Spring Boot集成Spring Statemachine

Spring Statemachine 是 Spring 框架下的一个模块,用于简化状态机的创建和管理,它允许开发者使用 Spring 的特性(如依赖注入、AOP 等)来构建复杂的状态机应用。以下是关于 Spring Statemachine 的详细介绍:

主要特性

  1. 丰富的状态机模型支持:支持多种状态机模型,如简单状态机、层次状态机和并行状态机。层次状态机允许状态嵌套,并行状态机可以同时处理多个独立的状态流。
  2. 灵活的配置方式:可以使用 Java 配置、XML 配置或注解来定义状态机的状态、转移、事件等。
  3. 与 Spring 生态集成:无缝集成 Spring 框架的其他模块,如 Spring Boot、Spring MVC 等,方便构建企业级应用。
  4. 事件驱动机制:通过事件触发状态转移,易于与外部系统进行交互。
  5. 状态监听器:允许开发者在状态转移前后执行自定义逻辑,如日志记录、业务处理等。

快速入门

1. 添加依赖

如果你使用 Maven,在 pom.xml 中添加以下依赖:

xml

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>3.2.1</version>
</dependency>
2. 定义状态和事件

java

// 定义状态枚举
public enum States {STATE1, STATE2, STATE3
}// 定义事件枚举
public enum Events {EVENT1, EVENT2
}
3. 配置状态机

使用 Java 配置方式:

java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {@Overridepublic void configure(StateMachineConfigurationConfigurer<States, Events> config) throws Exception {config.withConfiguration().autoStartup(true);}@Overridepublic void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {states.withStates().initial(States.STATE1).states(EnumSet.allOf(States.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {transitions.withExternal().source(States.STATE1).target(States.STATE2).event(Events.EVENT1).and().withExternal().source(States.STATE2).target(States.STATE3).event(Events.EVENT2);}
}
4. 使用状态机

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.statemachine.StateMachine;@SpringBootApplication
public class StateMachineApp implements CommandLineRunner {@Autowiredprivate StateMachine<States, Events> stateMachine;public static void main(String[] args) {SpringApplication.run(StateMachineApp.class, args);}@Overridepublic void run(String... args) throws Exception {stateMachine.start();System.out.println("当前状态: " + stateMachine.getState().getId());stateMachine.sendEvent(Events.EVENT1);System.out.println("触发 EVENT1 后状态: " + stateMachine.getState().getId());stateMachine.sendEvent(Events.EVENT2);System.out.println("触发 EVENT2 后状态: " + stateMachine.getState().getId());}
}

代码解释

  1. 定义状态和事件:使用枚举类型定义状态机的状态和事件,方便管理和使用。
  2. @Configuration:表明这是一个配置类。
  3. @EnableStateMachine:启用状态机功能。
  4. 配置状态机
    • configure(StateMachineConfigurationConfigurer):配置状态机的基本属性,如自动启动。
    • configure(StateMachineStateConfigurer):定义状态机的状态,指定初始状态STATE_A和所有可能的状态。
    • configure(StateMachineTransitionConfigurer):定义状态之间的转移规则,包括源状态、目标状态和触发事件。EVENT_1 事件触发从 STATE_A 到 STATE_B 的转移,EVENT_2 事件触发从 STATE_B 到 STATE_C 的转移。
  5. 使用状态机:在 CommandLineRunner 中注入状态机实例,启动状态机并发送事件,观察状态的变化。

应用场景

  1. 工作流管理:如订单处理流程、审批流程等,通过状态机可以清晰地管理每个步骤的状态转换。
  2. 游戏开发:管理游戏角色的状态,如站立、行走、攻击等,根据用户输入和游戏逻辑进行状态转移。
  3. 设备控制:控制物联网设备的状态,如智能家电的开关、模式切换等。

Spring Statemachine 提供了强大而灵活的功能,帮助开发者更高效地实现状态机应用。

-----------------------------------------------DEMO------------------------------------------------------------------

以下为你提供一个较为完整的 Spring Boot 集成 Spring Statemachine 的示例代码,这个示例模拟了一个简单的订单状态机,包含待支付、已支付、已发货、已完成几种状态。

1. 创建 Spring Boot 项目并添加依赖

可以使用 Spring Initializr 或者 IDE 自带的 Spring Boot 项目创建功能,添加以下依赖:

xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>3.2.1</version></dependency>
</dependencies>

2. 定义状态和事件枚举

java

// 定义订单状态枚举
public enum OrderState {PENDING_PAYMENT, PAID, SHIPPED, COMPLETED
}// 定义订单事件枚举
public enum OrderEvent {PAY, SHIP, DELIVER
}

3. 配置状态机

java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {@Overridepublic void configure(StateMachineConfigurationConfigurer<OrderState, OrderEvent> config) throws Exception {config.withConfiguration().autoStartup(true);}@Overridepublic void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception {states.withStates().initial(OrderState.PENDING_PAYMENT).states(EnumSet.allOf(OrderState.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {transitions.withExternal().source(OrderState.PENDING_PAYMENT).target(OrderState.PAID).event(OrderEvent.PAY).and().withExternal().source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP).and().withExternal().source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.DELIVER);}
}

4. 创建状态机服务类

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Service;@Service
public class OrderStateMachineService {@Autowiredprivate StateMachine<OrderState, OrderEvent> stateMachine;public boolean sendEvent(OrderEvent event) {return stateMachine.sendEvent(event);}public OrderState getCurrentState() {return stateMachine.getState().getId();}
}

5. 创建控制器类

java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/order")
public class OrderController {@Autowiredprivate OrderStateMachineService orderStateMachineService;@GetMapping("/currentState")public OrderState getCurrentState() {return orderStateMachineService.getCurrentState();}@PostMapping("/sendEvent/{event}")public String sendEvent(@PathVariable OrderEvent event) {boolean result = orderStateMachineService.sendEvent(event);if (result) {return "事件发送成功,当前状态: " + orderStateMachineService.getCurrentState();} else {return "事件发送失败,当前状态: " + orderStateMachineService.getCurrentState();}}
}

6. 启动 Spring Boot 应用

java

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

代码解释

  • 状态和事件枚举OrderState 定义了订单可能的状态,OrderEvent 定义了触发状态转移的事件。
  • 状态机配置OrderStateMachineConfig 类使用 @EnableStateMachine 注解启用状态机,通过重写三个配置方法分别配置状态机的基本属性、状态和转移规则。
  • 状态机服务类OrderStateMachineService 封装了状态机的操作,包括发送事件和获取当前状态。
  • 控制器类OrderController 提供了两个接口,一个用于获取当前订单状态,另一个用于发送事件触发状态转移。
  • 启动类SpringStatemachineDemoApplication 是 Spring Boot 应用的启动类。

测试

启动应用后,可以使用以下方式进行测试:

  • 获取当前状态:访问 http://localhost:8080/order/currentState
  • 发送事件:访问 http://localhost:8080/order/sendEvent/PAY 触发支付事件,根据状态机配置,订单状态将从 PENDING_PAYMENT 转移到 PAID

------------------------------------------------------------------------------------------------

transitions.withExternal().source(OrderState.PENDING_PAYMENT).target(OrderState.PAID).event(OrderEvent.PAY).and().withExternal().source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP).and().withExternal().source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.DELIVER);

这段代码的主要作用是定义状态机中不同状态之间的转移规则。在一个订单处理的状态机场景里,它明确了订单在不同状态(如待支付、已支付、已发货、已完成)之间如何根据特定事件(如支付、发货、交付)进行转换。

代码结构分析

整体上,这段代码通过多次调用 withExternal() 方法来定义多个外部状态转移规则,每个状态转移规则由 source(源状态)、target(目标状态)和 event(触发事件)三个关键部分组成,不同的状态转移规则之间通过 .and() 方法进行连接。

各部分详细解释

withExternal()

withExternal() 方法用于定义外部状态转移,即状态机从一个状态转移到另一个不同的状态。与之相对的还有内部转移(withInternal()),内部转移不会改变状态机的状态,只是在当前状态下执行一些操作。

.source(OrderState.PENDING_PAYMENT).target(OrderState.PAID).event(OrderEvent.PAY)
  • source(OrderState.PENDING_PAYMENT):指定状态转移的起始状态,这里是 OrderState.PENDING_PAYMENT,表示订单处于待支付状态。
  • target(OrderState.PAID):指定状态转移的目标状态,即 OrderState.PAID,意味着订单在满足条件后将转移到已支付状态。
  • event(OrderEvent.PAY):指定触发状态转移的事件,当 OrderEvent.PAY 事件发生时,状态机将从待支付状态转移到已支付状态。
.and()

and() 方法用于连接多个状态转移规则,它表示一个规则定义的结束和下一个规则定义的开始,使得可以在同一个配置方法中定义多个不同的状态转移规则。

后续规则

java

.withExternal().source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP)
.and()
.withExternal().source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.DELIVER);

这部分代码定义了另外两个状态转移规则:

  • 当 OrderEvent.SHIP 事件发生时,订单从已支付状态(OrderState.PAID)转移到已发货状态(OrderState.SHIPPED)。
  • 当 OrderEvent.DELIVER 事件发生时,订单从已发货状态(OrderState.SHIPPED)转移到已完成状态(OrderState.COMPLETED)。

示例代码扩展

如果需要在状态转移时执行一些额外的操作,比如记录日志或者更新数据库,可以使用 action() 方法。以下是一个扩展后的示例:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.action.Action;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {@Overridepublic void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {Action<OrderState, OrderEvent> payAction = context -> {System.out.println("订单已支付,更新订单状态为已支付");// 这里可以添加更新数据库等操作};Action<OrderState, OrderEvent> shipAction = context -> {System.out.println("订单已发货,更新订单状态为已发货");// 这里可以添加更新数据库等操作};Action<OrderState, OrderEvent> deliverAction = context -> {System.out.println("订单已完成,更新订单状态为已完成");// 这里可以添加更新数据库等操作};transitions.withExternal().source(OrderState.PENDING_PAYMENT).target(OrderState.PAID).event(OrderEvent.PAY).action(payAction).and().withExternal().source(OrderState.PAID).target(OrderState.SHIPPED).event(OrderEvent.SHIP).action(shipAction).and().withExternal().source(OrderState.SHIPPED).target(OrderState.COMPLETED).event(OrderEvent.DELIVER).action(deliverAction);}// 其他配置方法保持不变
}

在这个扩展示例中,通过定义 Action 对象,并在状态转移规则中使用 action() 方法,在状态转移时执行了相应的操作。

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

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

相关文章

数组总和 (leetcode 40

leetcode系列 文章目录 一、核心操作二、外层配合操作三、核心模式代码总结 去重方式和之前三数之和一样&#xff0c;也可以用used数组去重&#xff0c;但本次尝试使用set去重 一、核心操作 如果count为0了&#xff0c;则证明正好减到了0&#xff0c;就可以收获&#xff0c;…

sqli-lab靶场学习(八)——Less26-28

前言 25关已经出现了初步的一些关键字过滤&#xff0c;通过双写可以绕过。后面的关卡&#xff0c;我们会遇到更多关键字过滤&#xff0c;需要各种技巧绕过。 Less26 第26关写了会过滤空格和注释符。有很多的答案&#xff0c;会用%a0替代空格&#xff0c;但据说这是sqli-labs部…

python:VOC格式数据集转换为YOLO数据集格式

作者&#xff1a;CSDN _养乐多_ 本文将介绍如何将目标检测中常用的VOC格式数据集转换为YOLO数据集&#xff0c;并进行数据集比例划分&#xff0c;从而方便的进行YOLO目标检测。 如果不想分两步&#xff0c;可以直接看第三节代码。 文章目录 一、将VOC格式数据集转换为YOLO格…

Docker容器安装软件(完整版)

文章目录 一、安装Docker1.1 docker 相关的命令1.2 配置镜像加速 二. 安装es2.1 创建网络2.2 拉取镜像2.3 创建挂载点目录2.4 部署单点es&#xff0c;创建es容器2.5 编写elasticsearch.yml2.6 重启es容器2.7 测试Elasticsearch是否安装成功 三. 基于Docker安装Kibana3.1 拉取镜…

LINUX 指令大全

Linux服务器上有许多常用的命令&#xff0c;可以帮助你管理文件、目录、进程、网络和系统配置等。以下是一些常用的Linux命令&#xff1a; 文件和目录管理 ls&#xff1a;列出当前目录中的文件和子目录 bash lspwd&#xff1a;显示当前工作目录的路径 bash pwdcd&#xff1a;切…

燃气对我们生活的重要性体现在哪里?

燃气在我们的生活中有 多方面的重要性 &#xff0c;以下是燃气对我们生活的重要性的详细说明&#xff1a; 烹饪和热水供应 &#xff1a; 燃气是家庭烹饪的主要能源&#xff0c;能够快速、高效地加热食物&#xff0c;使家庭聚餐更加便捷和愉快。 燃气热水器能够在短时间内提供…

NetAssist 5.0.14网络助手基础使用及自动应答使用方案

以下是NetAssist v5.0.14自动应答功能的详细使用步骤&#xff1a; 一、基础准备&#xff1a; 工具下载网址页面&#xff1a;https://www.cmsoft.cn/resource/102.html 下载安装好后&#xff0c;根据需要可以创建多个server&#xff0c;双击程序图标运行即可&#xff0c;下面…

node.js-node.js作为服务器,前端使用WebSocket(单个TCP连接上进行全双工通讯的协议)

1.WebSocket全双工通信协议 WebSocket是HTML5开始提供的一种单个TCP连接上进行全双工通讯的协议。让客户端和服务器间的数据交互变得简单&#xff0c;允许服务端向客户端主动推送数据。浏览器和服务器间只需要完成一次握手&#xff0c;两者间创建持久性的连接&#xff0c;并进行…

java后端开发day31--集合进阶(一)-----Collection集合List集合数据结构1

&#xff08;以下内容全部来自上述课程&#xff09; 1.集合体系结构 List系列集合&#xff1a;添加的元素是有序、可重复、有索引。 Set系列集合&#xff1a;添加的元素是无序、不重复、无索引。 2.Collection集合 Collection是单列集合的祖宗接口&#xff08;不可直接创建…

Qt配置OpenGL相机踩的坑

项目根据LearnOpenGL配置Qt的相机&#xff0c;更新view矩阵和project矩阵的位移向量变得很大&#xff0c;我设置的明明相机位置是(0,0,3)&#xff0c;理想的位移向量刚好是相反数(0,0,-3)&#xff0c;对应的view矩阵位置向量可以变成(0,0,1200)…离模型非常远矩阵模型也看不见&…

【C++设计模式】第十六篇:迭代器模式(Iterator)

注意&#xff1a;复现代码时&#xff0c;确保 VS2022 使用 C17/20 标准以支持现代特性。 遍历聚合对象的统一方式 1. 模式定义与用途 核心思想 ​迭代器模式&#xff1a;提供一种方法顺序访问聚合对象的元素&#xff0c;而无需暴露其内部表示。关键用途&#xff1a; 1.​统一…

关于WPS的Excel点击单元格打开别的文档的两种方法的探究【为单元格添加超链接】

问题需求 目录和文件结构如下&#xff1a; E:\Dir_Level1 │ Level1.txt │ └─Dir_Level2│ Level2.txt│ master.xlsx│└─Dir_Level3Level3.txt现在要在master.xlsx点击单元格进而访问Level1.txt、Level2.txt、Level3.txt这些文件。 方法一&#xff1a;“单元格右键…

聚类中的相似矩阵和拉普拉斯矩阵

前言&#xff08;可以略过&#xff09; 最近在看的是关于聚类的论文&#xff0c;之前对聚类的步骤和相关内容不太了解&#xff0c;为了读懂论文就去学习了一下&#xff0c;这里将自己的理解记录下来。学习的不全面&#xff0c;主要是为了看懂论文&#xff0c;后续如果有涉及到聚…

前端笔记 --- vue框架

目录 基础知识 指令的修饰符 计算属性 watch侦听器的写法 Vue的生命周期 工程化开发&脚手架 VUE CLI 组件注册的方式 scoped样式冲突与原理 data 组件之间的关系和组件通信 v-model详解 sync修饰符 Dom介绍 操作HTML标签 总结 ref 和 $refs $nextTick 自…

智能双剑合璧:基于语音识别与大模型的技术沙龙笔记整理实战

智能双剑合璧&#xff1a;基于语音识别与大模型的技术沙龙笔记整理实战 ——记一次网络安全技术沙龙的高效知识沉淀 引言&#xff1a;当网络安全遇上AI生产力工具 在绿盟科技举办的"AI驱动的未来网络安全"内部技术沙龙中&#xff0c;笔者亲历了一场关于网络安全攻…

数据结构(蓝桥杯常考点)

数据结构 前言&#xff1a;这个是针对于蓝桥杯竞赛常考的数据结构内容&#xff0c;基础算法比如高精度这些会在下期给大家总结 数据结构 竞赛中&#xff0c;时间复杂度不能超过10的7次方&#xff08;1秒&#xff09;到10的8次方&#xff08;2秒&#xff09; 空间限制&#x…

使用 UNIX 命令在设计中搜索标识符:vcsfind 的入门指南

在现代软件开发和硬件设计中&#xff0c;快速准确地定位和搜索特定标识符是提高开发效率的关键。本文将介绍如何使用 UNIX 命令 vcsfind 在设计中搜索标识符&#xff0c;帮助您更高效地管理您的项目。 什么是 vcsfind&#xff1f; vcsfind 是一个强大的 UNIX 命令行工具&#x…

第56天:Web攻防-SQL注入增删改查盲注延时布尔报错有无回显错误处理审计复盘

#知识点 1、Web攻防-SQL注入-操作方法&增删改查 2、Web攻防-SQL注入-布尔&延时&报错&盲注 一、增删改查 1、功能&#xff1a;数据查询 查询&#xff1a;SELECT * FROM news where id$id 2、功能&#xff1a;新增用户&#xff0c;添加新闻等 增加&#xff1a;IN…

跳表实现学习

1.介绍 2.源码 跳表节点&#xff1a; /* ZSETs use a specialized version of Skiplists */ /*** brief 定义跳跃表节点的数据结构。* * 该结构体用于表示跳跃表中的一个节点&#xff0c;包含元素、分数、后向指针和多层链表信息。*/ typedef struct zskiplistNode {sds ele;…

Python:正则表达式

正则表达式的基础和应用 一、正则表达式核心语法&#xff08;四大基石&#xff09; 1. ​元字符&#xff08;特殊符号&#xff09;​ ​定位符 ^&#xff1a;匹配字符串开始位置 $&#xff1a;匹配字符串结束位置 \b&#xff1a;匹配单词边界​&#xff08;如 \bword\b 匹配…