Spring状态机简单实现

一、什么是状态机

状态机,又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的计算模型。状态机的概念其实可以应用的各种领域,包括电子工程、语言学、哲学、生物学、数学和逻辑学等,例如日常生活中的电梯、风扇、门闸机等,都会涉及到多种状态,随着动作的执行会进行状态的转移,而在软件编程领域,采用状态机的思路同样可以简化我们的设计流程,会使代码的可读性和可维护性得到增加。

目前用的比较多的开源状态机如:Spring StateMachine、Squirrel StateMachine以及阿里开源一款轻量的Cola-StateMachine,本文主要介绍Spring的状态机的使用。

二、Spring状态机的核心概念

  • transition:转换是原状态和目标状态之间的关系,用于将状态机从一种状态转移到另一种状态
  • source:节点的当前状态
  • target:节点的目标状态
  • event:触发节点从当前状态到目标状态的动作,如从State A 到 State B
  • guard:也叫“门卫”,当事件请求触发时,可以定义校验规则,用于校验是否可以执行后续action
  • action:用于实现当前节点对应的业务逻辑(事件发生之后系统做出的反应)
  • withChoice:当执行一个动作,可能导致多种结果时,可以选择使用choice+guard来跳转
  • withInternal:我们支持三种不同类型的转换,external,internal和local。转换时通过信号触发的,该信号是发送到状态机的事件或计时器

三、Spring状态机使用示例

Spring StateMachine 是 Spring 官方提供的状态机实现。其核心组件如下:

  • StateMachine:状态机实例,可以触发事件、执行状态转换,并获取当前状态等信息;
  • StateMachineStateConfigurer:用于配置状态,定义状态机中的各种状态,并指定每个状态的行为和属性;
  • StateMachineTransitionConfigurer:用于配置状态之间的转换关系,定义转换的触发事件、源状态、目标状态,以及转换的条件和动作;
  • StateMachineConfigurationConfigurer:状态机系统配置,用于配置状态机的全局属性和行为,包括状态机的执行模式、并发策略、监听器等;
  • StateMachineListenerAdapter:事件监听器,用于简化状态机事件监听器(StateMachineEventListener)的实现

这里还是以抽奖奖励状态转换为例,奖励的状态转换图如下:

在这里插入图片描述

  1. 环境准备:
<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-starter</artifactId><version>2.5.0</version></dependency>
  1. 定义奖励状态以及事件的枚举类

public enum AwardState {INACTIVE, ACTIVE, PAUSE, FINISH
}public enum AwardEvent {AUTO_ACTIVATE, AUTO_FINISH, FINISH, PAUSE, RESUME
}
  1. 状态机配置类:
@Configuration
@EnableStateMachine
public class AwardStateMachineConfig extends EnumStateMachineConfigurerAdapter<AwardState, AwardEvent> {@Autowiredprivate AwardStateMachineListener awardStateMachineListener;@Overridepublic void configure(StateMachineStateConfigurer<AwardState, AwardEvent> states) throws Exception {states.withStates().initial(AwardState.INACTIVE).states(EnumSet.allOf(AwardState.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<AwardState, AwardEvent> transitions) throws Exception {transitions.withExternal().source(AwardState.INACTIVE).target(AwardState.ACTIVE).event(AwardEvent.AUTO_ACTIVATE).and().withExternal().source(AwardState.INACTIVE).target(AwardState.FINISH).event(AwardEvent.AUTO_FINISH).and().withExternal().source(AwardState.ACTIVE).target(AwardState.FINISH).event(AwardEvent.FINISH).and().withExternal().source(AwardState.ACTIVE).target(AwardState.PAUSE).event(AwardEvent.PAUSE).and().withExternal().source(AwardState.PAUSE).target(AwardState.ACTIVE).event(AwardEvent.RESUME).and().withExternal().source(AwardState.PAUSE).target(AwardState.FINISH).event(AwardEvent.FINISH);}@Overridepublic void configure(StateMachineConfigurationConfigurer<AwardState, AwardEvent> config) throws Exception {config.withConfiguration().autoStartup(true).listener(awardStateMachineListener);}
}
  1. 状态机监听器:
@Component
public class AwardStateMachineListener extends StateMachineListenerAdapter<AwardState, AwardEvent> {@Overridepublic void transition(Transition<AwardState, AwardEvent> transition) {System.out.println("状态转移 from " + transition.getSource().getId() + " to " + transition.getTarget().getId());}/*@Overridepublic void stateChanged(State<AwardState, AwardEvent> from, State<AwardState, AwardEvent> to) {System.out.println("状态改变 from " + from.getId() + " to " + to.getId());}*/
}
  1. 奖励服务类
@Service
public class AwardStateMachineService {@Resourceprivate StateMachine<AwardState, AwardEvent> stateMachine;public void autoActivate() {stateMachine.sendEvent(AwardEvent.AUTO_ACTIVATE);}public void autoFinish() {stateMachine.sendEvent(AwardEvent.AUTO_FINISH);}public void finish() {stateMachine.sendEvent(AwardEvent.FINISH);}public void pause() {stateMachine.sendEvent(AwardEvent.PAUSE);}public void resume() {stateMachine.sendEvent(AwardEvent.RESUME);}}
  1. 测试:
@SpringBootTest
class AwardStatemachineApplicationTests {@Autowiredprivate AwardStateMachineService awardStateMachineService;@Autowiredprivate StateMachine<AwardState, AwardEvent> stateMachine;@Testvoid awardStageTest() {// 发送事件自动激活抽奖awardStateMachineService.autoActivate();// 检查状态是否变为ACTIVEassert (stateMachine.getState().getId() == AwardState.ACTIVE);// 发送事件暂停抽奖awardStateMachineService.pause();// 检查状态是否变为PAUSEassert (stateMachine.getState().getId() == AwardState.PAUSE);// 发送事件恢复抽奖awardStateMachineService.resume();// 检查状态是否变为ACTIVEassert (stateMachine.getState().getId() == AwardState.ACTIVE);// 发送事件结束抽奖awardStateMachineService.finish();// 检查状态是否变为FINISHassert (stateMachine.getState().getId() == AwardState.FINISH);}}

测试执行结果:
在这里插入图片描述
可以看到 Spring 状态机很好的控制了奖励状态之间的流转。

总结:本文主要介绍了Spring状态机的一些基本概念,以及状态流转的使用方式,Spring状态机一些高级的用法,如状态的持久化、状态的并行(parallel,fork,join)、子状态机等,会在后面文章更新。

参考:
https://docs.spring.io/spring-statemachine/docs/2.0.2.RELEASE/reference/htmlsingle/#glossary

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

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

相关文章

基于单片机的恒压供水控制器设计

摘 要 随着我国现代化的进程不断加快&#xff0c;城市居民生活水平不断提高&#xff0c;随之而来的是房屋的翻新和重建&#xff0c;但建筑层数的不断增高&#xff0c;使得供水所需压力不断提高&#xff0c;若建筑设计时对压力判断不足&#xff0c;会导致供水时无法供应到高楼层…

2.1HTML5基本结构

HTML5实际上不算是一种编程语言&#xff0c;而是一种标记语言。HTML5文件是由一系列成对出现的元素标签嵌套组合而成&#xff0c;这些标签以<元素名>的形式出现&#xff0c;用于标记文本内容的含义。浏览器通过元素标签解析文本内容并将结果显示在网页上&#xff0c;而元…

【Jenkins】data stream error|Error cloning remote repo ‘origin‘ 错误解决【亲测有效】

错误构建日志 17:39:09 ERROR: Error cloning remote repo origin 17:39:09 hudson.plugins.git.GitException: Command "git fetch --tags --progress http://domain/xxx.git refs/heads/*:refs/remotes/origin/*" returned status code 128: 17:39:09 stdout: 17…

多线程(代码案例: 单例模式, 阻塞队列, 生产者消费者模型,定时器)

设计模式是什么 类似于棋谱一样的东西 计算机圈子里的大佬为了能让小菜鸡的代码不要写的太差 针对一些典型的场景, 给出了一些典型的解决方案 这样小菜鸡们可以根据这些方案(ACM里面叫板子, 象棋五子棋里叫棋谱, 咱这里叫 设计模式), 略加修改, 这样代码再差也差不到哪里去 … …

clickhouse(配合bytebase)_docker搭建文档

特点 数据吞吐量非常大&#xff0c;能够存储海量的数据&#xff0c;并能够以水平扩展的方式进行扩容。对大表的查询计算处理效率也非常高&#xff0c;甚至很多场景下都可以拥有数百列的数据规模&#xff0c;很多大规模的数据查询也都能轻松达到毫秒级别 但需要指出&#xff0…

已解决org.apache.zookeeper.KeeperException.BadArgumentsException异常的正确解决方法,亲测有效!!!

已解决org.apache.zookeeper.KeeperException.BadArgumentsException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 控制数据大小&#xff1a;在写入数据前&#xff0c;检查数据大小是否超过限…

数码管的动态显示(三)

1.原理 data_reg寄存&#xff0c;只寄存符号位和数据位不包含小数点位。 动态数码管每个显示1ms&#xff0c;所以计数到5*10^4-1 为了将sel和seg同步&#xff0c;把sel打了一拍。 6位都使用到了可以这么计算&#xff0c;6位都显示的是数据。或者最高位显示的是小数点&#xff…

Flink广播流 BroadcastStream

文章目录 前言BroadcastStream代码示例Broadcast 使用注意事项 前言 Flink中的广播流&#xff08;BroadcastStream&#xff09;是一种特殊的流处理方式&#xff0c;它允许将一个流&#xff08;通常是一个较小的流&#xff09;广播到所有的并行任务中&#xff0c;从而实现在不同…

Yolo系列各代网络结构分析(一)

Yolo系列 Yolo系列算是目标检测领域的常青树了&#xff0c;从v1到最近的v9&#xff0c;一直都在不断迭代&#xff0c;不断改进&#xff0c;但是细看其各代网络的发展&#xff0c;其实还是有很多一脉相承之处以及算法设计偏好的&#xff0c;总结主要为以下几个方面&#xff1a;…

【计算机视觉】二、图像形成:1、向量和矩阵的基本运算:线性变换与齐次坐标

文章目录 一、向量和矩阵的基本运算1、简单变换1. 平移变换2. 缩放变换3. 旋转变换4. 一般线性变换 2、齐次坐标0. 齐次坐标表示1. 2D点的齐次坐标变换2. 投影空间 ( x , y , w ) (x, y, w) (x,y,w)3. 2D直线的齐次坐标表示a. 直线的参数方程表示b. 直线的法向量和原点距离表示…

深度解析Elasticsearch索引数据量过大的优化与部署策略

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 1. 分片和副本策略 1.1分片策略 1.1.1 数据量 1.1.…

sqllab第二十一关通关笔记

知识点&#xff1a; 错误注入 最大长度为32超过需要利用截取函数分段读取cookie注入base64加密会保留符号的原始属性 通过admin admin进行登录发现和第二十关显示的内容一样&#xff0c;猜测应该还是cookie注入&#xff1b; 直接截取带有cookie的数据包&#xff0c;发现uname…

【计算机网络】概述

文章目录 一、Internet 因特网1.1 网络、互联网、因特网1.2 因特网的组成 二、三种交换方式2.1 电路交换 &#xff08;Circuit Switching&#xff09;2.2 *分组交换 &#xff08;Packet Switching&#xff09;2.3 报文交换 &#xff08;Message Switching&#xff09; 三、计算…

100W-150W电阻器-TO-247模压厚膜电阻(1)

EAK封装的TO-247功率电阻器为设计工程师提供稳定的晶体管式封装的大功率电阻器件&#xff0c;功率为100W-150W。这些电阻器专为需要精度和稳定性的应用而设计。该电阻器采用氧化铝陶瓷层设计&#xff0c;可将电阻元件和安装片分开。 EAK模压TO-247厚膜功率电阻器 这种结构提供了…

Redis基本使用

Redis基本使用 1.通用命令2.基本数据类型2.1 String2.2 Hash2.3 List2.4 Set2.5 SortedSet 3. SpringDataRedis3.1 简介3.2 快速代码示例3.3 序列化 1.通用命令 针对所有数据类型的操作可以在Redis官方文档查看。以下是通用的命令。 KEYS&#xff1a;查看符合模板的所有key D…

React——react 的基本使用

前提&#xff1a;安装全局的脚手架&#xff0c;通过create-creat-app 项目名&#xff0c;我们创建好一个新项目&#xff0c;cd进去&#xff0c;通过npm start去运行该项目 注意&#xff1a;简单看下demo的配置&#xff0c;在根目录我们可以看到&#xff0c;没有任何webpack的…

SpringCloudGateway之统一鉴权篇

SpringCloudGateway之统一鉴权篇 SpringCloudGateway实现统一鉴权的方式 基于JWT&#xff08;JSON Web Token&#xff09; 在客户端登录成功后&#xff0c;服务端生成一个包含用户信息和过期时间等数据的JWT令牌返回给客户端。 客户端在后续请求中将此令牌放在请求头&#xf…

rviz上不显示机器人模型(模型只有白色)

文档中的是base_footprint&#xff0c;需要根据自己所设的坐标系更改&#xff0c;我的改为base_link 如何查看自己设的坐标系&#xff1a; 这些parent父坐标系就是 同时打开rviz后需要更改成base_link

Linux——使用Keepalived实现DHCP服务的高可用

前言 Keepalived是一个用于实现高可用性的开源工具&#xff0c;主要用于实现基于VRRP协议的负载均衡和故障转移功能。它可以通过检测节点的健康状况&#xff0c;并自动切换到备份节点来确保服务的高可用性。 Keepalived支持多种检测方式&#xff0c;如ping、TCP连接等&#x…

20232831 2023-2024-2 《网络攻防实践》第2次作业

目录 20232831 2023-2024-2 《网络攻防实践》第2次作业1.实验内容2.实验过程3.学习中遇到的问题及解决4.学习感悟、思考等参考资料 20232831 2023-2024-2 《网络攻防实践》第2次作业 1.实验内容 &#xff08;1&#xff09;从www.csdn.net、www.163.com等中选择一个DNS域名进行…