SpringBoot状态机

news2025/2/24 10:18:06

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
     */
    @Bean
    public DefaultStateMachinePersister<Object,Object,Order> persister() {
        return new DefaultStateMachinePersister<>(new StateMachinePersist<>() {
            @Override
            public void write(StateMachineContext<Object, Object> context, Order order) throws Exception {
                //todo 持久化处理
            }

            @Override
            public 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 {

    @Resource
    private StateMachine<OrderStatus, OrderEvents> orderStateMachine;

    @Resource
    private 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;
    }

    @SneakyThrows
    private 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.coloradmin.cn/o/2265607.html

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

相关文章

Redis基础知识分享(含5种数据类型介绍+增删改查操作)

一、redis基本介绍 1.redis的启动 服务端启动 pythonubuntu:~$ redis-server客户端启动 pythonubuntu:~$ redis-cli <127.0.0.1:6379> exit pythonubuntu:~$ redis-cli --raw //(支持中文的启动方式) <127.0.0.1:6379> exit2.redis基本操作 ping发送给服务器…

Pytorch注意力机制应用到具体网络方法(闭眼都会版)

文章目录 以YoloV4-tiny为例要加入的注意力机制代码模型中插入注意力机制 以YoloV4-tiny为例 解释一下各个部分&#xff1a; 最左边这部分为主干提取网络&#xff0c;功能为特征提取中间这边部分为FPN&#xff0c;功能是加强特征提取最后一部分为yolo head&#xff0c;功能为获…

交通控制系统中的 Prompt工程:引导LLMs实现高效交叉口管理 !

本研究提出了一种新型的交通控制系统方法&#xff0c;通过使用大型语言模型&#xff08;LLMs&#xff09;作为交通控制器。该研究利用它们的逻辑推理、场景理解和决策能力&#xff0c;实时优化通行能力并提供基于交通状况的反馈。LLMs将传统的分散式交通控制过程集中化&#xf…

产品升级!Science子刊同款ARGs-HOST分析,get!

凌恩生物明星chanpin 抗性宏基因-宿主分析 Science子刊同款分析 数据挖掘更进一步&#xff01; 抗生素的大量使用与滥用使微生物体内编码抗生素抗性的基因在环境中选择性富集&#xff0c;致病菌通过基因突变或者水平基因转移获得抗生素抗性基因后&#xff0c;导致抗生素治疗…

Python8-写一些小作业

记录python学习&#xff0c;直到学会基本的爬虫&#xff0c;使用python搭建接口自动化测试就算学会了&#xff0c;在进阶webui自动化&#xff0c;app自动化 python基础8-灵活运用顺序、选择、循环结构 写一些小练习题目1、给一个半径&#xff0c;求圆的面积和周长&#xff0c;…

四相机设计实现全向视觉感知的开源空中机器人无人机

开源空中机器人 基于深度学习的OmniNxt全向视觉算法OAK-4p-New 全景硬件同步相机 机器人的纯视觉避障定位建图一直是个难题&#xff1a; 系统实现复杂 纯视觉稳定性不高 很难选到实用的视觉传感器 为此多数厂家还是采用激光雷达的定位方案。 OAK-4p-New 为了弥合这一差距…

Diagramming AI: 使用自然语言来生成各种工具图

前言 在画一些工具图时&#xff08;流程图、UML图、架构图&#xff09;&#xff0c;你还在往画布上一个个的拖拽组件来进行绘制么&#xff1f;今天介绍一款更有效率的画图工具&#xff0c;它能够通过简单的自然语言描述来完成一个个复杂的图。 首页 进入官网之后&#xff0c;我…

springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失

这个包丢失了 启动不了 起因是pom中加入了 <tomcat.version></tomcat.version>版本指定&#xff0c;然后idea自动编译后&#xff0c;包丢了&#xff0c;删除这个配置后再也找不回来&#xff0c; 这个包正常在 <dependency><groupId>org.springframe…

“笃威尔数字技术”受邀出席2024 H-Tech Data创新情报论坛!

​ 2024年12月20日&#xff0c;以“创新情报 向新而行”为主题的2024 H-Tech Data创新情报论坛暨创新情报专业委员会成立仪式在深圳成功举办。本次大会由中国科学技术情报学会主办&#xff0c;由深圳国家高新技术产业创新中心牵头承办&#xff0c;旨在围绕技术赋能、场景应用、…

Android Studio 的革命性更新:Project Quartz 和 Gemini,开启 AI 开发新时代!

&#x1f31f; Android Studio 的革命性更新&#xff1a;Project Quartz 和 Gemini&#xff0c;开启 AI 开发新时代&#xff01; 在这个技术飞速发展的时代&#xff0c;Android 开发者们迎来了两项重大更新&#xff1a;Project Quartz 和 Gemini。这不仅仅是更新&#xff0c;而…

kkfileview代理配置,Vue对接kkfileview实现图片word、excel、pdf预览

kkfileview部署 官网&#xff1a;https://kkfileview.keking.cn/zh-cn/docs/production.html 这个是官网部署网址&#xff0c;这里推荐大家使用docker镜像部署&#xff0c;因为我是直接找运维部署的&#xff0c;所以这里我就不多说明了&#xff0c;主要说下nginx代理配置&am…

RT-DETR学习笔记(2)

七、IOU-aware query selection 下图是原始DETR。content query 是初始化为0的label embedding, position query 是通过nn.Embedding初始化的一个嵌入矩阵&#xff0c;这两部分没有任何的先验信息&#xff0c;导致DETR的收敛慢。 RT-DETR则提出要给这两部分&#xff08;conten…

iOS 苹果开发者账号: 查看和添加设备UUID 及设备数量

参考链接&#xff1a;苹果开发者账号下添加新设备UUID - 简书 如果要添加新设备到 Profiles 证书里&#xff1a; 1.登录开发者中心 Sign In - Apple 2.找到证书设置&#xff1a; Certificate&#xff0c;Identifiers&Profiles > Profiles > 选择对应证书 edit &g…

汽车IVI中控开发入门及进阶(47):CarPlay开发

概述: 车载信息娱乐(IVI)系统已经从仅仅播放音乐的设备发展成为现代车辆的核心部件。除了播放音乐,IVI系统还为驾驶员提供导航、通信、空调、电源配置、油耗性能、剩余行驶里程、节能建议和许多其他功能。 ​ 驾驶座逐渐变成了你家和工作场所之外的额外生活空间。2014年,…

Oracle、ACCSEE与TDMS的区别

Oracle、ACCSEE和TDMS都是不同类型的数据管理和存储工具&#xff0c;它们各自有独特的用途、结构和复杂性。Oracle是一个功能强大的关系型数据库管理系统&#xff0c;适用于大规模企业级应用&#xff0c;支持复杂查询和事务管理。ACCSEE主要应用于实时数据采集和过程监控&#…

商场消防电气控制系统设计(论文+源码)

1系统的功能及方案设计 如图2.1所示为本次设计的整体框图&#xff0c;其中单片机部分采用ST89C52来负责协调各个模块&#xff1b;液晶选择LCD1602液晶屏来显示信息;温度传感器选择PT1000进行温度的检测&#xff1b;烟雾传检测选择MQ2烟雾传感器&#xff1b;CO2检测选择CCS811模…

7. petalinux 根文件系统配置(package group)

根文件系统配置&#xff08;Petalinux package group&#xff09; 当使能某个软件包组的时候&#xff0c;依赖的包也会相应被使能&#xff0c;解决依赖问题&#xff0c;在配置页面的help选项可以查看需要安装的包 每个软件包组的功能: packagegroup-petalinux-audio包含与音…

2024年12月一区SCI-加权平均优化算法Weighted average algorithm-附Matlab免费代码

引言 本期介绍了一种基于加权平均位置概念的元启发式优化算法&#xff0c;称为加权平均优化算法Weighted average algorithm&#xff0c;WAA。该成果于2024年12月最新发表在中JCR1区、 中科院1区 SCI期刊 Knowledge-Based Systems。 在WAA算法中&#xff0c;加权平均位置代表当…

操作系统(23)外存的存储空间的管理

一、外存的基本概念与特点 定义&#xff1a;外存&#xff0c;也称为辅助存储器&#xff0c;是计算机系统中用于长期存储数据的设备&#xff0c;如硬盘、光盘、U盘等。与内存相比&#xff0c;外存的存储容量大、成本低&#xff0c;但访问速度相对较慢。特点&#xff1a;外存能够…

【202】仓库管理系统

-- 基于springboot仓库管理系统设计与实现 开发技术栈: 开发语言 : Java 开发软件 : Eclipse/MyEclipse/IDEA JDK版本 : JDK8 后端技术 : SpringBoot 前端技术 : Vue、Element、HTML、JS、CsS、JQuery 服务器 : Tomcat8/9 管理包 : Maven 数据库 : MySQL5.x/8 数据库工具 : …