目录

一、基本回顾

1、为什么要用状态机

2、什么是状态机

3、状态机可归纳为4个要素

4、对应Spring StateMachine的核心步骤

5、简单例子

添加maven依赖

定义状态枚举和事件枚举

完成状态机的配置

简单测试一下

添加Listener 监听器,当状态变更时,触发方法

添加拦截器

StateMachine 状态机实例

定义一个基于状态机实例的Handler

Springboot注入Handler和Listener bean的Configuration类

​编辑 注解方式使用

多个状态机共存

6、适用场景

二、测试注意


一、基本回顾

1、为什么要用状态机

系统状态和条件非常多、状态间切换复杂的场景,如何更好实现状态的切换:

方法1: if-else/switch方式实现,缺点是 代码可读性、可维护性差;

方式2:状态机实现。 本质上,状态机具备了多种优点,如 可读性好,可维护性高,以及容易扩展等等

2、什么是状态机

状态机(state machine)是一种行为,它指定对象在其生命周期内响应事件所经历的状态序列,以及对象对这些事件的响应

3、状态机可归纳为4个要素

即现态、条件、动作、次态。“现态”和“条件”是因,“动作”和“次态”是果。

现态:现在的状态。

条件:又称为“事件”,是一个动作发生的前提。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

4、对应Spring StateMachine的核心步骤

  • 定义状态枚举
  • 定义事件枚举
  • 定义状态机配置,设置初始状态,以及状态与事件之间的关系
  • 定义状态监听器,当状态变更时,触发方法

5、简单例子

添加maven依赖

<dependency><groupId>org.springframework.statemachine</groupId><artifactId>spring-statemachine-core</artifactId><version>2.0.1.RELEASE</version>
</dependency>

定义状态枚举和事件枚举

public enum CompanyStatus {WAIT_SUBMIT(0, "待企业实名"),WAIT_REAL_NAME(1, "待个人实名"),。。。CompanyStatus(int status, String desc) {this.status = status;this.desc = desc;
}
}public enum CompanyEvents {UNKNOWN_EVENT(0, "未知事件"),UN_REAL_NAME(1, "个人未实名事件"),REAL_NAME(2, "个人实名事件"),
...CompanyEvents(int value, String desc) {this.value = value;this.desc = desc;
}
}

完成状态机的配置

包括:(1)状态机的初始状态和所有状态;(2)状态之间的转移规则

@Configuration
@EnableStateMachineFactory(name = "companyStateMachineFactory")
public class CompanyStateMachineConfig extends EnumStateMachineConfigurerAdapter<CompanyStatus, CompanyEvents> {@Overridepublic void configure(StateMachineStateConfigurer<CompanyStatus, CompanyEvents> states) throws Exception {states.withStates()// 定义初始状态.initial(CompanyStatus.WAIT_SUBMIT)// 定义所有状态集合.states(EnumSet.allOf(CompanyStatus.class));}@Overridepublic void configure(StateMachineTransitionConfigurer<CompanyStatus, CompanyEvents> transitions) throws Exception {transitions.withExternal().source(CompanyStatus.WAIT_SUBMIT).target(CompanyStatus.WAIT_REAL_NAME).event(CompanyEvents.UN_REAL_NAME).and().withExternal().source(CompanyStatus.WAIT_SUBMIT).target(CompanyStatus.WAIT_CHECK).event(CompanyEvents.COMPANY_SUBMITED).and().withExternal()
...}
}

简单测试一下

启动状态机、发送不同的事件,通过日志验证状态机的流转过程

@ResourceStateMachine<CompanyStatus, CompanyEvents> stateMachine;public void createStateMachine(){stateMachine.start();stateMachine.sendEvent(CompanyEvents.UN_REAL_NAME);stateMachine.sendEvent(CompanyEvents.REAL_NAME);}

添加Listener 监听器,当状态变更时,触发方法

public interface PersistStateChangeListener {/*** 当状态被持久化,调用此方法** @param state* @param message* @param transition* @param stateMachine 状态机实例*/void onPersist(State<CompanyStatus, CompanyEvents> state, Message<CompanyEvents> message,Transition<CompanyStatus, CompanyEvents> transition, StateMachine<CompanyStatus, CompanyEvents> stateMachine);
}@Slf4j
@Component("companyPersistStateChangeListener")
public class CompanyPersistStateChangeListener implements PersistStateChangeListener {
...真正实现}

添加拦截器

不同于Listener。其可以改变状态转移链的变化。

主要在preEvent(事件预处理)、preStateChange(状态变更的前置处理)、postStateChange(状态变更的后置处理)、preTransition(转化的前置处理)、postTransition(转化的后置处理)、stateMachineError(异常处理)等执行点生效。

private class PersistingStateChangeInterceptor extends StateMachineInterceptorAdapter<CompanyStatus, CompanyEvents> {@Overridepublic void preStateChange(State<CompanyStatus, CompanyEvents> state, Message<CompanyEvents> message,Transition<CompanyStatus, CompanyEvents> transition, StateMachine<CompanyStatus,CompanyEvents> stateMachine) {listeners.onPersist(state, message, transition, stateMachine);}}

StateMachine 状态机实例

StateMachine 状态机实例,spring statemachine支持单例、工厂模式两种方式创建。

每个statemachine有一个独有的machineId用于标识machine实例;

需要注意的是statemachine实例内部存储了当前状态机等上下文相关的属性,因此这个实例不能够被多线程共享。

例如:工厂模式创建实例

定义一个基于状态机实例的Handler

为了方便扩展更多的Listener,以及管理Listeners和Interceptors。可以定义一个基于状态机实例的Handler: PersistStateMachineHandler,以及持久化实体的监听器。

Springboot注入Handler和Listener bean的Configuration类

 注解方式使用

@Slf4j
@Service
public class TestService {@PostConstruct
private void initialize() {this.persistStateMachineHandler.addPersistStateChangeListener(companyPersistStateChangeListener);
}public void userToDoSomething() {...//userToDoSomethingpersistStateMachineHandler.handleEventWithState(MessageBuilder.withPayload(events).setHeader("company", company.getId()).build(), CompanyStatus.of(status));}}

多个状态机共存

在实际项目中一般都会有多个状态机并发执行,比如订单,同一时刻会有不止一个订单在运行,而每个订单都有自己的订单状态机流程。想要实现多个状态机的并行执行,就需要用到builder.

6、适用场景

各种审核逻辑业务: 如 财务审核、交易业务、TOB结算业务审核、合同状态

订单支付类业务: 如 商家单据,订单会有多种状态:已下单、待支付、已支付、待发货、待收货、已完成、退款中、退款成功等等

二、测试注意

  • 单个业务场景下,状态流转正常;
  • 状态异常流转时兼容处理;
  • 并发操作,分别流转到不同状态正常

spring-statemachine状态机梳理相关推荐

  1. Spring系列学习之Spring Statemachine状态机

    英文原文:https://projects.spring.io/spring-statemachine/ 目录 快速开始 Builder JavaConfig 版本 资源 实战 Spring Stat ...

  2. Spring StateMachine,教你快速实现一个状态机

    来源:http://t.cn/RIxCXiO Spring StateMachine框架可能对于大部分使用Spring的开发者来说还比较生僻,它的主要功能是帮助开发者简化状态机的开发过程,让状态机结构 ...

  3. 使用Spring StateMachine框架实现状态机

    Spring StateMachine框架可能对于大部分使用Spring的开发者来说还比较生僻,该框架目前差不多也才刚满一岁多.它的主要功能是帮助开发者简化状态机的开发过程,让状态机结构更加层次化.前 ...

  4. spring statemachine的企业可用级开发指南1-说些废话

    2019独角兽企业重金招聘Python工程师标准>>> 1.背景 在我打算学习spring statemachine的时候,我几乎看过了所有网上的中文教程,基本上都处于浅尝辄止的阶段 ...

  5. Spring StateMachine(2) UML状态图支持

    还是刚才的以二级审批请假流程为例. 绘制流程 首先创建 Papyrus 项目,选择 StateMachine 模板,绘制流程图如下: 然后创建 6 个 signal event 和与之绑定的 sign ...

  6. Spring Statemachine 简介

    Spring Statemachine 简介 Spring Statemachine是Spring官方提供的一个框架,供应用程序开发人员在Spring应用程序中使用状态机.支持状态的嵌套(substa ...

  7. Spring Statemachine TODO

    为什么80%的码农都做不了架构师?>>>    编者注 之前自己实现的完整的有限状态机,具有事件能够传值的特点,个人很喜欢.最近又需要实现有限状态机,对于值传递没有要求,则可以使用通 ...

  8. 2021最新Spring Security知识梳理

    2021最新Spring Security知识梳理 一.SpringSecurity 框架简介 Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spri ...

  9. Spring高级技术梳理

    Spring高级技术梳理 序言 正文 SpringData部分 Spring全家桶之SpringData--预科阶段 Spring全家桶之SpringData--Spring 整合Hibernate与 ...

最新文章

  1. 广播风暴系列专题(一)广播风暴:发现-端口
  2. R语言-包的安装、载入及使用方法
  3. psp能装安卓软件吗_王思聪:翻译软件能翻译出文化吗?
  4. sigprocmask 阻塞进程
  5. elementuiDemo1.1
  6. 命令不识别_互助问答138期:GMM命令代码中如何识别年份国家及异方差检验问题...
  7. 采用递归求第n位数【C#】
  8. 获取进程列表和结束进程
  9. 优先级管理器 IPriorityManager -- ESBasic 可复用的.NET类库(14)
  10. hadoop集群虚拟机配置
  11. jQuery form插件使用详解
  12. php留言板制作模板,简单5步,制作wordpress留言板
  13. 解决连接kudu时,delaying RPC due to Service unavailable: Master config (**.**.**.**:7051) has no leader
  14. codeforces228A Is your horseshoe on the other hoof?(水题)
  15. 史上屌炸天超详细的Java实现逆波兰表达式
  16. java 短连接转长连接_HTTP的长连接和短连接转换接口(API)
  17. 计算机屏幕背景设置方法,高清电脑桌面壁纸如何设置,教您设置系统主题美化方法...
  18. chrome 设置搜索结果,在新的标签页打开
  19. android平板可以连硬盘,平板电脑可以连接移动硬盘吗 平板电脑连接不上硬盘怎么办...
  20. C# 6 与 .NET Core 1.0 高级编程 - 41 ASP.NET MVC(上)

热门文章

  1. python数据挖掘商业案例_Python数据科学-技术详解与商业实践-第八讲作业
  2. 心胸有多大事就能做多大
  3. 逆波兰表达式-----------红黑树--------mysql(DDL)----生产者消费者模式
  4. [Vant] van-tabs标签页吸顶\/粘性布局在移动端适配上的一些尝试
  5. 腾讯IM即时通讯(2.4.1)
  6. 桃源婚恋交友APP-计算机毕业设计源码
  7. 基于Kafka+ELK搭建海量日志平台
  8. 51CTO博客2.0造星计划——粉丝大奖赛参赛名单,你关注了吗?
  9. Java——成绩等级评定
  10. 非常可乐 (bfs)HDU - 1495