springboot接入Spring State Machine实现状态机

描述

在 Spring Boot 中实现状态机,通常使用 Spring State Machine 框架进行实现。该框架可以帮助我们定义、创建和管理复杂的状态机。

接下来给出一个demo,说明如何使用 Spring State Machine 框架实现状态机。

假设我们需要实现一个简单的订单状态机,订单的状态可以是已创建、已确认、已发货、已完成和已取消。在订单生命周期中,可以有以下事件:

- 确认订单(confirmOrder):从已创建状态转换到已确认状态。

- 发货(shipOrder):从已确认状态转换到已发货状态。

- 确认收货(receiveOrder):从已发货状态转换到已完成状态。

- 取消订单(cancelOrder):从已创建或已确认状态转换到已取消状态。

现在让我们来实现这个订单状态机。

代码

在 pom.xml 文件中添加以下依赖:

```xml

<dependency>

    <groupId>org.springframework.statemachine</groupId>

    <artifactId>spring-statemachine-core</artifactId>

    <version>2.1.2.RELEASE</version>

</dependency>

```

对于该状态机,我们可以定义以下枚举:状态以及事件

```java

public enum States {

    CREATED, CONFIRMED, SHIPPED, COMPLETED, CANCELLED

}

```

```java

public enum Events {

    CONFIRM_ORDER, SHIP_ORDER, RECEIVE_ORDER, CANCEL_ORDER

}

```

创建一个状态机配置类,用于管理状态机的定义和创建。从 StateMachineConfigurerAdapter 继承,并添加 @Configuration 和 @EnableStateMachine 注解。

```java

@Configuration

@EnableStateMachine

public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<States, Events> {

    @Override

    public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {

        states

                .withStates()

                .initial(States.CREATED)

                .state(States.CONFIRMED)

                .state(States.SHIPPED)

                .state(States.COMPLETED)

                .state(States.CANCELLED)

                .end(States.COMPLETED)

                .end(States.CANCELLED);

    }

    @Override

    public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {

        transitions

                .withExternal()

                .source(States.CREATED)

                .target(States.CONFIRMED)

                .event(Events.CONFIRM_ORDER)

                .and()

                .withExternal()

                .source(States.CONFIRMED)

                .target(States.SHIPPED)

                .event(Events.SHIP_ORDER)

                .and()

                .withExternal()

                .source(States.SHIPPED)

                .target(States.COMPLETED)

                .event(Events.RECEIVE_ORDER)

                .and()

                .withExternal()

                .source(States.CREATED)

                .target(States.CANCELLED)

                .event(Events.CANCEL_ORDER)

                .and()

                .withExternal()

                .source(States.CONFIRMED)

                .target(States.CANCELLED)

                .event(Events.CANCEL_ORDER);

    }

}

```

在上述通过 Config 注解启用了 State Machine 的例子中,我们定义了状态机的状态和事件转换,分别是通过 configure 方法实现 StateMachineStateConfigurer 和 StateMachineTransitionConfigurer。我们定义了订单状态和事件,定义了每个状态可以发生的转换,其中 withExternal() 表示外部转换。

接下来,我们创建一个状态机服务,该服务将使用上述状态机配置进行初始化,然后使用状态机按照规定的转换流程进行状态转换。

```java

@Service

public class OrderStateMachineService {

    @Autowired

    private StateMachine<States, Events> stateMachine;

    public boolean sendEvent(final String orderId, final Events event) {

        stateMachine.start();

        Message<Events> message = MessageBuilder.withPayload(event)

                .setHeader("orderId", orderId)

                .build();

        return stateMachine.sendEvent(message);

    }

}

```

我们注入了 StateMachine<States, Events> 类型的 stateMachine 对象,并定义了一个事件触发方法 sendEvent()。该方法通过设置事件消息的负载,将事件发送给状态机进行状态转换。

我们测试一下:

```java

@RestController

@RequestMapping("/order")

public class OrderController {

    @Autowired

    private OrderStateMachineService orderStateMachineService;

    @PostMapping("/confirm")

    public boolean confirmOrder(@RequestBody final Order order) {

        return orderStateMachineService.sendEvent(order.getId(), Events.CONFIRM_ORDER);

    }

    @PostMapping("/ship")

    public boolean shipOrder(@RequestBody final Order order) {

        return orderStateMachineService.sendEvent(order.getId(), Events.SHIP_ORDER);

    }

    @PostMapping("/receive")

    public boolean receiveOrder(@RequestBody final Order order) {

        return orderStateMachineService.sendEvent(order.getId(), Events.RECEIVE_ORDER);

    }

    @PostMapping("/cancel")

    public boolean cancelOrder(@RequestBody final Order order) {

        return orderStateMachineService.sendEvent(order.getId(), Events.CANCEL_ORDER);

    }

}

```

测试结果如下:

1、以上接口依次调用,程序正常;

2、不按顺序调用,会报错

优缺点说明:

1、这种实现方式会受集群部署影响,因为这些状态是存在内存中的,当然可以通过其它方式解决,比如持久化道数据库中;

2、如果订单周期比较长,并且数据量比较大,放在内存中,会引发oom;

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

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

相关文章

SocialFi 和 GameFi 的碰撞 — Socrates 构建新的 Web3 流量入口

伴随着比特币现货 ETF 即将通过 SEC 批准的消息&#xff0c;整个加密市场在11月份达到了熊市以来的新高峰。市场普遍上涨&#xff0c;新的玩法和项目不断涌出吸引了大量老用户回归以及新用户加入。加密市场经过长期的低迷&#xff0c;终于来到了牛市的起点&#xff01; 上一轮牛…

Selenium 连接到现有的 Firefox 示例

当前环境&#xff1a; python 3.7 selenium 3.14.1 urllib3 1.26.8 Frefox 115.1.0esr(32位) geckodriver.exe 0.33.0 1 下载 Firefox 浏览器&#xff0c;根据自己的需要选择。 下载 Firefox 浏览器&#xff0c;这里有简体中文及其他 90 多种语言版本…

什么是依赖倒置原则

1、什么是依赖倒置原则 依赖倒置原则&#xff08;Dependency Inversion Principle&#xff0c;DIP&#xff09;是指高层模块不应该依赖于低层模块&#xff0c;它们都应该依赖于抽象。换句话说&#xff0c;具体类之间的依赖关系应该尽可能减少&#xff0c;而抽象类或接口之间的…

C语言自定义函数的整数处理

1.输入10个整数&#xff0c;将其中最小的数与第一个数对换&#xff0c;把最大的数与最后一个数对换。写三个函数&#xff1b; ①输入10个数&#xff1b;②进行处理&#xff1b;③输出10个数。 示例输入&#xff1a; 2 1 3 4 5 6 7 8 10 9 示例输出&#xff1a; 1 2 3 4 5 6…

Python交互式解释器及用法

为了让开发者能快速学习、测试 Python 的各种功能&#xff0c;Python 提供的“python”命令不仅能用于运行 Python 程序&#xff0c;也可作为一个交互式解释器一一开发者逐行输入 Python 代码&#xff0c;它逐行解释执行。 当输入“python”命令时&#xff0c;可以看到如下输出…

带你用uniapp从零开发一个仿小米商场_10. 首页开发

图标菜单栏开发 轮播图开发完成后,就是图标菜单栏了 可以看出这些图标都是一样的样式,所以可以勇哥flex布局让他们每个占百分之20 代码如下,既然都是一样的那就直接用个循环嵌套一下 data数据如下 同样,为了能让这段代码能在别的地方也用到,我直接把它封装成组件 <templ…

Spring 注解

Spring部分 声明bean的注解 Component: 组件&#xff0c;没有明确的角色在这里插入代码片Service: 在业务逻辑层使用&#xff08;service层&#xff09;Repository: 在数据访问层使用&#xff08;dao层&#xff09;Controller: 在展现层使用&#xff0c;控制器的声明&#xff0…

ClickHouse:真正的OLAP列式DBMS

ClickHouse 1、本文持续更新... 1、本文持续更新… ClickHouse官方文档&#xff1a;https://clickhouse.com/docs/zh

Go 基本数据类型

一、内置类型 1、值类型&#xff1a; bool int(32 or 64),int8,int16,int32,int64 uint(32 or 64),uint8(byte),uint16,uint32,uint64 float32,float64 string complex64,complex128 array //固定长度的数组2、引用类型&#xff1a;&#xff08;指针类型&#xff09; sli…

【Element】el-switch开关 点击弹窗确认框时状态先改变----点击弹窗取消框失效

一、背景 需求&#xff1a;在列表中添加定期出账的开关按钮&#xff0c;点击开关时&#xff0c;原来的状态不改变&#xff0c;弹出弹窗&#xff1b;点击弹窗取消按钮&#xff1a;状态不改变&#xff0c;点击弹窗确定按钮&#xff1a;状态改变&#xff0c;并调取列表数据刷新页…

LINUX入门篇【10】---进程篇【2】---进程状态

前言&#xff1a; 有了上一篇关于进程的初步认识和我们的PCB第一个数据段–标识符的讲解&#xff0c;接下来我们将继续讲解PCB的其他数据段&#xff0c;本篇要讲的是进程状态。 进程状态&#xff1a; 就像我们写贪吃蛇的时候&#xff0c;构建的游戏状态来判定游戏结束的方式…

vue实现对话框指定某个对话内容的滚动到指定位置(滚动到可视区域的中间位置)

1、使用el-scrollbar实现定位滚动&#xff08;elementui组件库&#xff09; 如何滚动&#xff1a;参考链接 比如说指定某条对话内容滚动到可视区域的中间 html结构&#xff1a; <div class"chat-list" id"chat-list"><el-scrollbar ref"scro…

代码随想录算法训练营第六十天|84. 柱状图中最大的矩形

84. 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释…

C--51--WiFi模块ESP-01S ( 路由服务器 )

ESP-01S当成服务器&#xff1a; 1、接线 &#xff08;接CH340接入pc&#xff09; USB转TTL插入电脑&#xff0c;TX/RX交叉接线&#xff0c;VCC接5V&#xff0c;GND接地 查询IP地址&#xff1a;ATCIFSR 2、建立AT指令使能连接 一、配置网络调试助手 协议类型&#xff1a;TCP C…

Linux——使用命令查看文件和文件夹数量

目录 一、相关命令参数解析二、查看当前目录下的文件数量2.1 包含子目录中的文件2.2 不包含子目录中的目录 三、查看当前目录下的文件夹个数3.1 不包含目录中的目录3.2 包含目录中的目录 四、查看当前文件夹下叫某某的文件的数量实例 五、总结 一、相关命令参数解析 "&qu…

java方法引用

MethodReference 前言特定类任意方法引用函数接口特定类调用 前言 JDK1.8之后提供是Lambda&#xff0c;它可以让开发者自定义函数接口中抽象方法的实现&#xff0c;方法引用可以让开发者直接引用已存在的方法。 方法引用的形式: 类::静态方法 类::特定类任意方法 对象::实例方…

MyBatis 操作数据库(入门)

一&#xff1a;MyBatis概念 (1)MyBatis &#x1f497;MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发 (2)持久层 1.持久层 &#x1f49c;持久层&#xff1a;持久化操作的层&#xff0c;通常指数据访问层(dao)&#xff0c;是用来操作数据库的 2.持久层的规范 ①…

leetcode_828 统计子串中的唯一字符

1. 题意 统计一个字符串的所有子串中唯一字符的数量。 例如: "ABA"的字串对应的唯一字符数量 “A”&#xff1a; 1 “AB”&#xff1a;2 “ABA”&#xff1a;1 “B”&#xff1a;1 “BA”&#xff1a;2 “A”&#xff1a;1 求和为8 统计子串中的唯一字符 2. 题解 …

Doris的数据模型

Doris 的数据模型主要分为3类:Aggregate、Uniq、Duplicate 1 Aggregate 模型 表中的列按照是否设置了AggregationType,分为 Key(维度列)和 Value(指标列)。没有设置AggregationType的称为 Key,设置了AggregationType的称为Value。 当我们导入数据时,对于Key列相同的行会…

竞赛选题 题目:基于卷积神经网络的手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…