Spring Boot 揭秘与实战(七) 实用技术篇 - StateMachine 状态机机制

文章目录

  1. 1. 环境依赖
  2. 2. 状态和事件
    1. 2.1. 状态枚举
    2. 2.2. 事件枚举
  3. 3. 状态机配置4. 状态监听器
    1. 3.1. 初始化状态机状态
    2. 3.2. 初始化状态迁移事件
  4. 5. 总结
  5. 6. 源代码

Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。

之前,我们使用二维数组实现状态机机制,现在,我们来用 Spring StateMachine 进行改造。

环境依赖

修改 POM 文件,添加 spring-statemachine-core 依赖。

  1. <dependency>
  2. <groupId>org.springframework.statemachine</groupId>
  3. <artifactId>spring-statemachine-core</artifactId>
  4. <version>1.2.0.RELEASE</version>
  5. </dependency>

状态和事件

现在,我以用户注册为案例,来讲解状态和事件之间的状态机机制。

状态枚举

注册有哪些状态呢,我们来想想,应该有4个状态:未连接、已连接、注册中、已注册。

  1. public enum RegStatusEnum {
  2.  
  3. // 未连接
  4. UNCONNECTED,
  5. // 已连接
  6. CONNECTED,
  7. // 注册中
  8. REGISTERING,
  9. // 已注册
  10. REGISTERED;
  11.  
  12. }

事件枚举

相对应的,存在几个核心事件:连接、注册、注册成功、注册失败、注销。

  1. public enum RegEventEnum {
  2. // 连接
  3. CONNECT,
  4. // 注册
  5. REGISTER,
  6. // 注册成功
  7. REGISTER_SUCCESS,
  8. // 注册失败
  9. REGISTER_FAILED,
  10. // 注销
  11. UN_REGISTER;
  12. }

状态机配置

  1. @Configuration
  2. @EnableStateMachine
  3. public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<RegStatusEnum, RegEventEnum> {
  4.  
  5. }

@EnableStateMachine注解,标识启用 Spring StateMachine 状态机功能。

初始化状态机状态

我们需要初始化状态机的状态。

  1. @Override
  2. public void configure(StateMachineStateConfigurer<RegStatusEnum, RegEventEnum> states) throws Exception {
  3. states.withStates()
  4. // 定义初始状态
  5. .initial(RegStatusEnum.UNCONNECTED)
  6. // 定义状态机状态
  7. .states(EnumSet.allOf(RegStatusEnum.class));
  8. }

其中,initial(RegStatusEnum.UNCONNECTED) 定义了初始状态是未连接状态。states(EnumSet.allOf(RegStatusEnum.class)) 定义了定义状态机中存在的所有状态。

初始化状态迁移事件

我们需要初始化当前状态机有哪些状态事件。

  1. @Override
  2. public void configure(StateMachineTransitionConfigurer<RegStatusEnum, RegEventEnum> transitions)
  3. throws Exception {
  4. transitions
  5. // 1.连接事件
  6. // 未连接 -> 已连接
  7. .withExternal()
  8. .source(RegStatusEnum.UNCONNECTED)
  9. .target(RegStatusEnum.CONNECTED)
  10. .event(RegEventEnum.CONNECT)
  11. .and()
  12.  
  13. // 2.注册事件
  14. // 已连接 -> 注册中
  15. .withExternal()
  16. .source(RegStatusEnum.CONNECTED)
  17. .target(RegStatusEnum.REGISTERING)
  18. .event(RegEventEnum.REGISTER)
  19. .and()
  20.  
  21. // 3.注册成功事件
  22. // 注册中 -> 已注册
  23. .withExternal()
  24. .source(RegStatusEnum.REGISTERING)
  25. .target(RegStatusEnum.REGISTERED)
  26. .event(RegEventEnum.REGISTER_SUCCESS)
  27. .and()
  28.  
  29. // 5.注销事件
  30. // 已连接 -> 未连接
  31. .withExternal()
  32. .source(RegStatusEnum.CONNECTED)
  33. .target(RegStatusEnum.UNCONNECTED)
  34. .event(RegEventEnum.UN_REGISTER)
  35. .and()
  36. // 注册中 -> 未连接
  37. .withExternal()
  38. .source(RegStatusEnum.REGISTERING)
  39. .target(RegStatusEnum.UNCONNECTED)
  40. .event(RegEventEnum.UN_REGISTER)
  41. .and()
  42. // 已注册 -> 未连接
  43. .withExternal()
  44. .source(RegStatusEnum.REGISTERED)
  45. .target(RegStatusEnum.UNCONNECTED)
  46. .event(RegEventEnum.UN_REGISTER)
  47. ;
  48. }

这里,我以连接事件为案例,其中 source 指定原始状态,target 指定目标状态,event 指定触发事件。

因此,下面的状态就很好理解了,即当发生连接事件时,从未连接状态变更为已连接状态。

  1. // 未连接 -> 已连接
  2. .withExternal()
  3. .source(RegStatusEnum.UNCONNECTED)
  4. .target(RegStatusEnum.CONNECTED)
  5. .event(RegEventEnum.CONNECT)

状态监听器

Spring StateMachine 提供了注解配置实现方式,所有 StateMachineListener 接口中定义的事件都能通过注解的方式来进行配置实现。

  1. @WithStateMachine
  2. public class StateMachineEventConfig {
  3.  
  4. @OnTransition(source = "UNCONNECTED", target = "CONNECTED")
  5. public void connect() {
  6. System.out.println("///////////////////");
  7. System.out.println("连接事件, 未连接 -> 已连接");
  8. System.out.println("///////////////////");
  9. }
  10.  
  11. @OnTransition(source = "CONNECTED", target = "REGISTERING")
  12. public void register() {
  13. System.out.println("///////////////////");
  14. System.out.println("注册事件, 已连接 -> 注册中");
  15. System.out.println("///////////////////");
  16. }
  17.  
  18. @OnTransition(source = "REGISTERING", target = "REGISTERED")
  19. public void registerSuccess() {
  20. System.out.println("///////////////////");
  21. System.out.println("注册成功事件, 注册中 -> 已注册");
  22. System.out.println("///////////////////");
  23. }
  24.  
  25. @OnTransition(source = "REGISTERED", target = "UNCONNECTED")
  26. public void unRegister() {
  27. System.out.println("///////////////////");
  28. System.out.println("注销事件, 已注册 -> 未连接");
  29. System.out.println("///////////////////");
  30. }
  31. }

这里,我仍然以连接事件为案例,@OnTransition 中 source 指定原始状态,target 指定目标状态,当事件触发时将会被监听到从而调用 connect() 方法。

总结

Spring StateMachine 让状态机结构更加层次化,可以帮助开发者简化状态机的开发过程。

我们来回顾下几个核心步骤

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

源代码

相关示例完整代码: springboot-action

(完)

 

微信公众号
posted @   long77  阅读(8406)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
点击右上角即可分享
微信分享提示