企业怎么建设自己的网站首页,成都网站游戏设计,电商营销策划方案范文,商丘网站开发1、概述 Spring State Machine 是一个用于处理状态机逻辑的框架#xff0c;它提供了一种简洁的方法来定义状
态、转换以及在状态变更时触发的动作。
概念 状态 #xff08; State #xff09; #xff1a;一个状态机至少要包含两个状态。例如自动门的例子#xff0c;有 …1、概述 Spring State Machine 是一个用于处理状态机逻辑的框架它提供了一种简洁的方法来定义状
态、转换以及在状态变更时触发的动作。
概念 状态 State 一个状态机至少要包含两个状态。例如自动门的例子有 open 和 closed 两个状态。 事件 Event 事件就是执行某个操作的触发条件或者口令。对于自动门“按下开门按钮”就是一个事件。 动作 Action 事件发生以后要执行动作。例如事件是“按开门按钮”动作是“开门”。编程的时候一个 Action一般就对应一个函数。 转换 Transition 也就是从一个状态变化为另一个状态。例如“开门过程”就是一个转换。 守卫Guard 一种条件逻辑用于决定是否可以进行某个状态转换。守卫可以基于应用程序的当前状态或其他条件来确定转换是否应该发生。
状态机 有限状态机Finite-state machine,FSM又称有限状态自动机简称状态机是表示有限
个状态以及在这些状态之间的转移和动作等行为的数学模型。FSM是一种算法思想简单而言有
限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组
成。其作用主要是描述对象在它的生命周期内所经历的状态序列以及如何响应来自外界的各种事
件。
地址
官方地址
Spring Statemachine
文档地址
Spring Statemachine - Reference Documentation
github地址
https://github.com/spring-projects/spring-statemachine
2、状态机图 做需求时需要了解以下六种元素起始、终止、现态、次态目标状态、动作、条件
我们就可以完成一个状态机图了以订单为例通过支付事件订单状态从待支付状态转换为待发货状态。 现态是指当前所处的状态。待支付。条件又称为“事件”当一个条件被满足将会触发一个动作或者执行一次状态的迁移。支付事件。动作条件满足后执行的动作。动作执行完毕后可以迁移到新的状态也可以仍旧保持原状态。动作不是必需的当条件满足后也可以不执行任何动作直接迁移到新状态。状态转换为待发货。次态条件满足后要迁往的新状态。“次态”是相对于“现态”而言的“次态”一旦被激活就转变成新的“现态”了。待发货。
注意事项:
避免把某个“程序动作”当作是一种“状态”来处理。那么如何区分“动作”和“状态”“动作”是不稳定的即使没有条件的触发“动作”一旦执行完毕就结束了而“状态”是相对稳定的如果没有外部条件的触发一个状态会一直持续下去。状态划分时漏掉一些状态导致跳转逻辑不完整。所以在设计状态机时我们需要反复的查看设计的状态图或者状态表最终达到一种牢不可破的设计方案。
3、代码
3.1 依赖 !--spring 状态机start--
dependencygroupIdorg.springframework.statemachine/groupIdartifactIdspring-statemachine-core/artifactIdversion${spring-statemachine.version}/version
/dependency
!-- redis持久化状态机 --
dependencygroupIdorg.springframework.statemachine/groupIdartifactIdspring-statemachine-data-redis/artifactIdversion${spring-statemachine.version}/version
/dependency
!--spring 状态机end--
!--redis start--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
!--redis end--
3.2 定义状态和事件
package com.ybw.constant;/*** 状态** author weixiansheng* version V1.0* className RegStatusEnum* date 2023/12/26**/
public enum RegStatusEnum {// 未连接UNCONNECTED,// 已连接CONNECTED,// 注册中REGISTERING,// 已注册REGISTERED;
}package com.ybw.constant;/*** 事件** author weixiansheng* version V1.0* className RegEventEnum* date 2023/12/26**/
public enum RegEventEnum {// 连接CONNECT,// 注册REGISTER,// 注册成功REGISTER_SUCCESS,// 注册失败REGISTER_FAILED,// 注销UN_REGISTER;
}3.3 配置状态机
创建一个配置类来配置状态机。在这个配置中我们定义状态转换逻辑。
package com.ybw.config;import com.ybw.constant.RegEventEnum;
import com.ybw.constant.RegStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.EnumSet;/*** author weixiansheng* version V1.0* className StateMachineConfig* date 2023/12/25**/
Configuration
EnableStateMachine
Slf4j
public class StateMachineConfig extends EnumStateMachineConfigurerAdapterRegStatusEnum, RegEventEnum {/*** 配置状态** param states* methodName: configure* return: void* author: weixiansheng* date: 2023/12/25**/Overridepublic void configure(StateMachineStateConfigurerRegStatusEnum, RegEventEnum states) throws Exception {states.withStates()// 定义初始状态.initial(RegStatusEnum.UNCONNECTED)// 定义状态机状态.states(EnumSet.allOf(RegStatusEnum.class));}/*** 配置状态转换事件关系** param transitions* methodName: configure* return: void* author: weixiansheng* date: 2023/12/25**/Overridepublic void configure(StateMachineTransitionConfigurerRegStatusEnum, RegEventEnum transitions) throws Exception {transitions// 1.连接事件// 未连接 - 已连接.withExternal().source(RegStatusEnum.UNCONNECTED).target(RegStatusEnum.CONNECTED).event(RegEventEnum.CONNECT).and()// 2.注册事件// 已连接 - 注册中.withExternal().source(RegStatusEnum.CONNECTED).target(RegStatusEnum.REGISTERING).event(RegEventEnum.REGISTER).and()// 3.注册成功事件// 注册中 - 已注册.withExternal().source(RegStatusEnum.REGISTERING).target(RegStatusEnum.REGISTERED).event(RegEventEnum.REGISTER_SUCCESS).and()// 5.注销事件// 已连接 - 未连接.withExternal().source(RegStatusEnum.CONNECTED).target(RegStatusEnum.UNCONNECTED).event(RegEventEnum.UN_REGISTER).and()// 注册中 - 未连接.withExternal().source(RegStatusEnum.REGISTERING).target(RegStatusEnum.UNCONNECTED).event(RegEventEnum.UN_REGISTER).and()// 已注册 - 未连接.withExternal().source(RegStatusEnum.REGISTERED).target(RegStatusEnum.UNCONNECTED).event(RegEventEnum.UN_REGISTER);}
}3.4 状态机的转换事件配置
package com.ybw.config;import com.alibaba.fastjson2.JSON;
import com.ybw.constant.RegEventEnum;
import com.ybw.entity.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;
import org.springframework.statemachine.annotation.OnTransition;
import org.springframework.statemachine.annotation.WithStateMachine;/*** 状态机的转换事件配置** author weixiansheng* version V1.0* className StateMachineEventConfig* date 2023/12/26**/
WithStateMachine
Slf4j
public class StateMachineEventConfig {/*** 连接事件** param message* methodName: connect* return: void* author: weixiansheng* date: 2023/12/26**/OnTransition(source UNCONNECTED, target CONNECTED)public void connect(MessageRegEventEnum message) {Order order (Order) message.getHeaders().get(order);log.info(///);log.info(连接事件, 未连接 - 已连接,order:{}, JSON.toJSONString(order));log.info(///);}/*** 注册事件** param message* methodName: register* return: void* author: weixiansheng* date: 2023/12/26**/OnTransition(source CONNECTED, target REGISTERING)public void register(MessageRegEventEnum message) {log.info(///);log.info(注册事件, 已连接 - 注册中);log.info(///);}/*** 注册成功事件** param message* methodName: registerSuccess* return: void* author: weixiansheng* date: 2023/12/26**/OnTransition(source REGISTERING, target REGISTERED)public void registerSuccess(MessageRegEventEnum message) {log.info(///);log.info(注册成功事件, 注册中 - 已注册);log.info(///);}/*** 注销事件** param message* methodName: unRegister* return: void* author: weixiansheng* date: 2023/12/26**/OnTransition(source REGISTERED, target UNCONNECTED)public void unRegister(MessageRegEventEnum message) {log.info(///);log.info(注销事件, 已注册 - 未连接);log.info(///);}
}3.6 Redis持久化
持久化到redis中在分布式系统中使用。
package com.ybw.config;import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.statemachine.data.redis.RedisStateMachineContextRepository;
import org.springframework.statemachine.data.redis.RedisStateMachinePersister;
import org.springframework.statemachine.persist.RepositoryStateMachinePersist;/*** 持久化** author weixiansheng* version V1.0* className Persist* date 2023/12/26**/
Configuration
Slf4j
public class PersistE, S {Resourceprivate RedisConnectionFactory redisConnectionFactory;/*** 持久化到redis中在分布式系统中使用** methodName: getRedisPersister* return: org.springframework.statemachine.data.redis.RedisStateMachinePersisterE, S* author: weixiansheng* date: 2023/12/26**/Bean(name stateMachineRedisPersister)public RedisStateMachinePersisterE, S getRedisPersister() {RedisStateMachineContextRepositoryE, S repository new RedisStateMachineContextRepository(redisConnectionFactory);RepositoryStateMachinePersistE, S p new RepositoryStateMachinePersist(repository);return new RedisStateMachinePersister(p);}
}3.6 测试
package com.ybw.state;import com.ybw.constant.RegEventEnum;
import com.ybw.constant.RegStatusEnum;
import com.ybw.entity.Order;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.data.redis.RedisStateMachinePersister;
import org.springframework.statemachine.persist.StateMachinePersister;/*** author weixiansheng* version V1.0* className StateTest* date 2023/12/26**/
SpringBootTest
Slf4j
public class StateTest {Resourceprivate StateMachineRegStatusEnum, RegEventEnum stateMachine;Resource(name stateMachineRedisPersister)private RedisStateMachinePersisterRegStatusEnum, RegEventEnum persister;/*** MethodName: testState* Description:* Param: []* Return: void* Author: ybwei* Date: 2020/3/26**/Testpublic void testState() {try {Order order Order.builder().id(1L).name(张三).status(RegStatusEnum.CONNECTED).build();stateMachine.start();//尝试恢复状态机状态(read)persister.restore(stateMachine, order.getId().toString());MessageRegEventEnum message MessageBuilder.withPayload(RegEventEnum.CONNECT).setHeader(order, order).build();stateMachine.sendEvent(message);//持久化状态机状态(write)persister.persist(stateMachine, order.getId().toString());} catch (Exception e) {log.error(testState error:, e);}
// stateMachine.sendEvent(RegEventEnum.REGISTER);
// stateMachine.sendEvent(RegEventEnum.REGISTER_SUCCESS);
// stateMachine.sendEvent(RegEventEnum.UN_REGISTER);
//
// stateMachine.sendEvent(RegEventEnum.CONNECT);}
}执行结果
第一次执行
[INFO ] 2023-12-26 17:35:20.563 [main] o.s.s.support.AbstractStateMachine - Got null context, resetting to initial state, clearing extended state and machine id
[INFO ] 2023-12-26 17:35:20.593 [main] c.ybw.config.StateMachineEventConfig - ///
[INFO ] 2023-12-26 17:35:20.688 [main] c.ybw.config.StateMachineEventConfig - 连接事件, 未连接 - 已连接,order:{id:1,name:张三,status:CONNECTED}
[INFO ] 2023-12-26 17:35:20.690 [main] c.ybw.config.StateMachineEventConfig - ///
第二次执行没有日志打印。
修改代码
将RegEventEnum.CONNECT改为RegEventEnum.REGISTER
Test
public void testState() {try {Order order Order.builder().id(1L).name(张三).status(RegStatusEnum.CONNECTED).build();stateMachine.start();//尝试恢复状态机状态(read)persister.restore(stateMachine, order.getId().toString());MessageRegEventEnum message MessageBuilder.withPayload(RegEventEnum.REGISTER).setHeader(order, order).build();stateMachine.sendEvent(message);//持久化状态机状态(write)persister.persist(stateMachine, order.getId().toString());} catch (Exception e) {log.error(testState error:, e);}
}
第三次执行打印日志
[INFO ] 2023-12-26 17:38:31.307 [main] c.ybw.config.StateMachineEventConfig - ///
[INFO ] 2023-12-26 17:38:31.307 [main] c.ybw.config.StateMachineEventConfig - 注册事件, 已连接 - 注册中
[INFO ] 2023-12-26 17:38:31.307 [main] c.ybw.config.StateMachineEventConfig - /// 总结
事件发生后会执行StateMachineEventConfig相关逻辑。持久化状态机状态。相同的事件再次发生不会执行StateMachineEventConfig相关逻辑。
3.7 源码地址
share: 分享仓库 - Gitee.com