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

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM