Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制
文章目录
Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。
之前,我们使用二维数组实现状态机机制,现在,我们来用 Spring StateMachine 进行改造。
环境依赖
修改 POM 文件,添加 spring-statemachine-core 依赖。
- <dependency>
- <groupId>org.springframework.statemachine</groupId>
- <artifactId>spring-statemachine-core</artifactId>
- <version>1.2.0.RELEASE</version>
- </dependency>
状态和事件
现在,我以用户注册为案例,来讲解状态和事件之间的状态机机制。
状态枚举
注册有哪些状态呢,我们来想想,应该有4个状态:未连接、已连接、注册中、已注册。
- public enum RegStatusEnum {
- // 未连接
- UNCONNECTED,
- // 已连接
- CONNECTED,
- // 注册中
- REGISTERING,
- // 已注册
- REGISTERED;
- }
事件枚举
相对应的,存在几个核心事件:连接、注册、注册成功、注册失败、注销。
- public enum RegEventEnum {
- // 连接
- CONNECT,
- // 注册
- REGISTER,
- // 注册成功
- REGISTER_SUCCESS,
- // 注册失败
- REGISTER_FAILED,
- // 注销
- UN_REGISTER;
- }
状态机配置
- @Configuration
- @EnableStateMachine
- public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<RegStatusEnum, RegEventEnum> {
- }
@EnableStateMachine注解,标识启用 Spring StateMachine 状态机功能。
初始化状态机状态
我们需要初始化状态机的状态。
- @Override
- public void configure(StateMachineStateConfigurer<RegStatusEnum, RegEventEnum> states) throws Exception {
- states.withStates()
- // 定义初始状态
- .initial(RegStatusEnum.UNCONNECTED)
- // 定义状态机状态
- .states(EnumSet.allOf(RegStatusEnum.class));
- }
其中,initial(RegStatusEnum.UNCONNECTED) 定义了初始状态是未连接状态。states(EnumSet.allOf(RegStatusEnum.class)) 定义了定义状态机中存在的所有状态。
初始化状态迁移事件
我们需要初始化当前状态机有哪些状态事件。
- @Override
- public void configure(StateMachineTransitionConfigurer<RegStatusEnum, 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)
- ;
- }
这里,我以连接事件为案例,其中 source 指定原始状态,target 指定目标状态,event 指定触发事件。
因此,下面的状态就很好理解了,即当发生连接事件时,从未连接状态变更为已连接状态。
- // 未连接 -> 已连接
- .withExternal()
- .source(RegStatusEnum.UNCONNECTED)
- .target(RegStatusEnum.CONNECTED)
- .event(RegEventEnum.CONNECT)
状态监听器
Spring StateMachine 提供了注解配置实现方式,所有 StateMachineListener 接口中定义的事件都能通过注解的方式来进行配置实现。
- @WithStateMachine
- public class StateMachineEventConfig {
- @OnTransition(source = "UNCONNECTED", target = "CONNECTED")
- public void connect() {
- System.out.println("///////////////////");
- System.out.println("连接事件, 未连接 -> 已连接");
- System.out.println("///////////////////");
- }
- @OnTransition(source = "CONNECTED", target = "REGISTERING")
- public void register() {
- System.out.println("///////////////////");
- System.out.println("注册事件, 已连接 -> 注册中");
- System.out.println("///////////////////");
- }
- @OnTransition(source = "REGISTERING", target = "REGISTERED")
- public void registerSuccess() {
- System.out.println("///////////////////");
- System.out.println("注册成功事件, 注册中 -> 已注册");
- System.out.println("///////////////////");
- }
- @OnTransition(source = "REGISTERED", target = "UNCONNECTED")
- public void unRegister() {
- System.out.println("///////////////////");
- System.out.println("注销事件, 已注册 -> 未连接");
- System.out.println("///////////////////");
- }
- }
这里,我仍然以连接事件为案例,@OnTransition 中 source 指定原始状态,target 指定目标状态,当事件触发时将会被监听到从而调用 connect() 方法。
总结
Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。
我们来回顾下几个核心步骤
- 定义状态枚举。
- 定义事件枚举。
- 定义状态机配置,设置初始状态,以及状态与事件之间的关系。
- 定义状态监听器,当状态变更时,触发方法。
源代码
相关示例完整代码: springboot-action
(完)
如果觉得我的文章对你有帮助,请随意打赏。

- 版权声明:本文由 梁桂钊 发表于 梁桂钊的博客
- 转载声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证),非商业转载请注明作者及出处,商业转载请联系作者本人。
- 文章标题:Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制
- 文章链接:http://blog.720ui.com/2017/springboot_07_othercore_statemachine/
Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制的更多相关文章
- Spring Boot 揭秘与实战(七) 实用技术篇 - 异步任务
文章目录 1. Spring Boot 集成异步任务 2. 单发服务模式 3. 请求应答模式 4. 源代码 Spring 对异步任务具有很好的支持.这篇文章,我们透过 Spring Boot 来讲解下 ...
- Spring Boot 揭秘与实战(七) 实用技术篇 - Java Mail 发送邮件
文章目录 1. Spring Boot 集成 Java Mail 2. 单元测试 3. 源代码 Spring 对 Java Mail 有很好的支持.因此,Spring Boot 也提供了自动配置的支持 ...
- Spring Boot 揭秘与实战(七) 实用技术篇 - FreeMarker 模板引擎
文章目录 1. FreeMaker 代替 JSP 作为页面渲染 2. 生成静态文件 3. 扩展阅读 4. 源代码 Spring Boot 提供了很多模板引擎的支持,例如 FreeMarker.Thym ...
- Spring Boot 揭秘与实战 附录 - Spring Boot 公共配置
Spring Boot 公共配置,配置 application.properties/application.yml 文件中. 摘自:http://docs.spring.io/spring-boot ...
- Spring Boot 揭秘与实战 自己实现一个简单的自动配置模块
文章目录 1. 实战的开端 – Maven搭建 2. 参数的配置 - 属性参数类 3. 真的很简单 - 简单的服务类 4. 自动配置的核心 - 自动配置类 5. spring.factories 不要 ...
- Spring Boot 揭秘与实战 源码分析 - 工作原理剖析
文章目录 1. EnableAutoConfiguration 帮助我们做了什么 2. 配置参数类 – FreeMarkerProperties 3. 自动配置类 – FreeMarkerAutoCo ...
- Spring Boot 揭秘与实战 源码分析 - 开箱即用,内藏玄机
文章目录 1. 开箱即用,内藏玄机 2. 总结 3. 源代码 Spring Boot提供了很多”开箱即用“的依赖模块,那么,Spring Boot 如何巧妙的做到开箱即用,自动配置的呢? 开箱即用,内 ...
- Spring Boot 揭秘与实战(九) 应用监控篇 - 自定义监控端点
文章目录 1. 继承 AbstractEndpoint 抽象类 2. 创建端点配置类 3. 运行 4. 源代码 Spring Boot 提供的端点不能满足我们的业务需求时,我们可以自定义一个端点. 本 ...
- Spring Boot 揭秘与实战(九) 应用监控篇 - HTTP 健康监控
文章目录 1. 内置 HealthIndicator 监控检测 2. 自定义 HealthIndicator 监控检测 3. 源代码 Health 信息是从 ApplicationContext 中所 ...
随机推荐
- pycharm下打开、执行并调试scrapy爬虫程序
首先得有一个Scrapy项目,我在Desktop上新建一个Scrapy的项目叫test,在Desktop目录打开命令行,键入命令:scrapy startproject test1 目录结构如下: ...
- Python3各种进制之间的转换方法
一.2/8/10/16进制互转 1.1 2/8/10/16进制赋值 # 二进制赋值以0b打头 a = 0b1000 # 八进制赋值以0o打头,第一个是数字0第二个是字母o b = 0o1100 # 十 ...
- redis集群搭建教程(以3.2.2为例)
redis从3.0版本开始支持集群,2.X版本主支持sentinel主从模式:所以要搭建集群务必下载3.0以上版本,本教程以3.2.2版本为例. redis集群最少要有3个主节点,最典型的是3主3从组 ...
- npm run build 打包后,如何运行在本地查看效果(Apache服务)
目前,使用vue-cli脚手架写了一个前端项目,之前一直是使用npm run dev 在8080端口上进行本地调试.项目已经进行一半了,今天有时间突然想使用npm run build进行上线打包,试试 ...
- Win10系列:UWP界面布局进阶1
全新的Windows 10 操作系统支持多种视图模式,用户可以根据需要选择不同的视图模式显示应用.当用户同时浏览或操作多个应用程序时,可以将应用视图调整为辅屏视图或填充视图,这样在一个屏幕中可以同时对 ...
- Linux command nmon
Linux command nmon [Purpose] Learning linux command nmon [Eevironment] Ubuntu 16.04 ...
- Resharper插件安装和破解
1.首先在最下面的地址,下载Resharper安装包,进行解压安装,安装界面如下: a 2.安装后 解压下载好的 文件 会得到如下: 3.打开序列号 会看到如下所示: 4.然后 复制 %LocalA ...
- 十七. Python基础(17)--正则表达式
十七. Python基础(17)--正则表达式 1 ● 正则表达式 定义: Regular expressions are sets of symbols that you can use to cr ...
- 深入理解java虚拟机---java虚拟机内存管理(五)
1.深入理解java虚拟机 总图: 1.线程共享区: 2.线程独占区: 1.程序计数器 理解为当前线程锁执行的字节码的行号指示器,程序计数器没有内存异常错误.
- 3.10 C++虚基类 虚继承
参考:http://www.weixueyuan.net/view/6367.html 总结: 本例即为典型的菱形继承结构,类A中的成员变量及成员函数继承到类D中均会产生两份,这样的命名冲突非常的棘手 ...