1、什么是状态机
1.1 什么是状态
先来解释什么是“状态”( State )。现实事物是有不同状态的,例如一个自动门,就有 open 和 closed 两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有限个,例如自动门的状态就是两个 open 和 closed 。

状态机,也就是 State Machine ,不是指一台实际机器,而是指一个数学模型。说白了,一般就是指一张状态转换图。例如,根据自动门的运行规则,我们可以抽象出下面这么一个图。
自动门有两个状态,open 和 closed ,closed 状态下,如果读取开门信号,那么状态就会切换为 open 。open 状态下如果读取关门信号,状态就会切换为 closed 。
状态机的全称是有限状态自动机,自动两个字也是包含重要含义的。给定一个状态机,同时给定它的当前状态以及输入,那么输出状态时可以明确的运算出来的。例如对于自动门,给定初始状态 closed ,给定输入“开门”,那么下一个状态时可以运算出来的。
这样状态机的基本定义我们就介绍完毕了。重复一下:状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
最近建了一些工作内推群,各大城市都有,欢迎各位HR和找工作的小伙伴进群交流,群里目前已经收集了不少的工作内推岗位。
1.2 四大概念
下面来给出状态机的四大概念。
-
第一个是 State ,状态。一个状态机至少要包含两个状态。例如上面自动门的例子,有 open 和 closed 两个状态。
-
第二个是 Event ,事件。事件就是执行某个操作的触发条件或者口令。对于自动门,“按下开门按钮”就是一个事件。
-
第三个是 Action ,动作。事件发生以后要执行动作。例如事件是“按开门按钮”,动作是“开门”。编程的时候,一个 Action一般就对应一个函数。
-
第四个是 Transition ,变换。也就是从一个状态变化为另一个状态。例如“开门过程”就是一个变换。
1.3 状态机
有限状态机(Finite-state machine,FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
FSM是一种算法思想,简单而言,有限状态机由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。
其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。
2、状态机图
做需求时,需要了解以下六种元素:起始、终止、现态、次态(目标状态)、动作、条件,我们就可以完成一个状态机图了:
以订单为例:以从待支付状态转换为待发货状态为例

-
①现态:是指当前所处的状态。待支付
-
②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。支付事件
-
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。状态转换为待发货
-
④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。待发货 注意事项
1、避免把某个“程序动作”当作是一种“状态”来处理。那么如何区分“动作”和“状态”?“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;而“状态”是相对稳定的,如果没有外部条件的触发,一个状态会一直持续下去。
2、状态划分时漏掉一些状态,导致跳转逻辑不完整。所以在设计状态机时,我们需要反复的查看设计的状态图或者状态表,最终达到一种牢不可破的设计方案。另外,推荐公众号Java精选,回复java面试,获取在线面试资料,支持随时随地刷题。
3、spring statemachine
3.1 状态机spring statemachine 概述
Spring Statemachine是应用程序开发人员在Spring应用程序中使用状态机概念的框架。关于更多spring架构知识:https://www.yoodb.com/spring/spring-ioc-architecture.html
Spring Statemachine旨在提供以下功能:
-
易于使用的扁平单级状态机,用于简单的使用案例。
-
分层状态机结构,以简化复杂的状态配置。
-
状态机区域提供更复杂的状态配置。
-
使用触发器,转换,警卫和操作。
-
键入安全配置适配器。
-
生成器模式,用于在Spring Application上下文之外使用的简单实例化通常用例的食谱
-
基于Zookeeper的分布式状态机
-
状态机事件监听器。
-
UML Eclipse Papyrus建模。
-
将计算机配置存储在永久存储中。
-
Spring IOC集成将bean与状态机关联起来。
状态机功能强大,因为行为始终保证一致,使调试相对容易。这是因为操作规则是在机器启动时写成的。这个想法是你的应用程序可能存在于有限数量的状态中,某些预定义的触发器可以将你的应用程序从一个状态转移到另一个状态。此类触发器可以基于事件或计时器。
在应用程序之外定义高级逻辑然后依靠状态机来管理状态要容易得多。您可以通过发送事件,侦听更改或仅请求当前状态来与状态机进行交互。官网:https://spring.io/projects/spring-statemachine
3.2 快速开始
以订单状态扭转的例子为例:
表结构设计如下:
CREATE TABLE`tb_order` (
`id`bigint(20) unsignedNOTNULL AUTO_INCREMENT COMMENT'主键ID',
`order_code`varchar(128) COLLATE utf8mb4_bin DEFAULTNULLCOMMENT'订单编码',
`status`smallint(3) DEFAULTNULLCOMMENT'订单状态',
`name`varchar(64) COLLATE utf8mb4_bin DEFAULTNULLCOMMENT'订单名称',
`price`decimal(12,2) DEFAULTNULLCOMMENT'价格',
`delete_flag`tinyint(2) NOTNULLDEFAULT'0'COMMENT'删除标记,0未删除 1已删除',
`create_time`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'创建时间',
`update_time`timestampNOTNULLDEFAULT'0000-00-00 00:00:00'COMMENT'更新时间',
`create_user_code`varchar(32) COLLATE utf8mb4_bin DEFAULTNULLCOMMENT'创建人',
`update_user_code`varchar(32) COLLATE utf8mb4_bin DEFAULTNULLCOMMENT'更新人',
`version`int(11) NOTNULLDEFAULT'0'COMMENT'版本号',
`remark`varchar(64) COLLATE utf8mb4_bin DEFAULTNULLCOMMENT'备注',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6DEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='订单表';
/*Data for the table `tb_order` */
insertinto`tb_order`(`id`,`order_code`,`status`,`name`,`price`,`delete_flag`,`create_time`,`update_time`,`create_user_code`,`update_user_code`,`version`,`remark`) values
(2,'A111',1,'A','22.00',0,'2022-10-15 16:14:11','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
(3,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
(4,'A111',1,'订单A','22.00',0,'2022-10-02 21:53:13','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL),
(5,'A111',1,'订单A','22.00',0,'2022-10-03 09:08:30','2022-10-02 21:29:14','zhangsan','zhangsan',0,NULL);
1)引入依赖
<!-- redis持久化状态机 -->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-redis</artifactId>
<version>1.2.9.RELEASE</version>
</dependency>
<!--状态机-->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-starter</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
2)定义状态机状态和事件
状态枚举:
publicenum OrderStatus {
// 待支付,待发货,待收货,已完成
WAIT_PAYMENT(1, "待支付"),
WAIT_DELIVER(2, "待发货"),
WAIT_RECEIVE(3, "待收货"),
FINISH(4, "已完成");
private Integer key;
private String desc;
OrderStatus(Integer key, String desc) {
this.key = key;
this.desc = desc;
}
public Integer getKey() {
return key;
}
public String getDesc() {
return desc;
}
public static OrderStatus getByKey(Integer key) {
for (OrderStatus e : values()) {
if (e.getKey().equals(key)) {
return e;
}
}
thrownew RuntimeException("enum not exists.");
}
}
事件:
public enum OrderStatusChangeEvent {
// 支付,发货,确认收货
PAYED, DELIVERY, RECEIVED;
}
3)定义状态机规则和配置状态机
@Configuration
@EnableStateMachine(name = "orderStateMachine")
publicclass OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {
/**
* 配置状态
*
* @param states
* @throws Exception
*/
public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
states
.withStates()
.initial(OrderStatus.WAIT_PAYMENT)
.states(EnumSet.allOf(OrderStatus.class));
}
/**
* 配置状态转换事件关系
*
* @param transitions
* @throws Exception
*/
public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
transitions
//支付事件:待支付-》待发货
.withExternal().source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER).event(OrderStatusChangeEvent.PAYED)
.and()
//发货事件:待发货-》待收货
.withExternal().source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE).event(OrderStatusChangeEvent.DELIVERY)
.and()
&nb

最低0.47元/天 解锁文章
1743

被折叠的 条评论
为什么被折叠?



