Spring Boot 揭祕與實戰(七) 實用技術篇 - StateMachine 狀態機機制

原文地址:Spring Boot 揭祕與實戰(七) 實用技術篇 - StateMachine 狀態機機制
博客地址:blog.720ui.com/javascript

Spring StateMachine 讓狀態機結構更加層次化,能夠幫助開發者簡化狀態機的開發過程。以前,咱們使用二維數組實現狀態機機制,如今,咱們來用 Spring StateMachine 進行改造。java

環境依賴

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

<dependency>
    <groupId>org.springframework.statemachine</groupId>
    <artifactId>spring-statemachine-core</artifactId>
    <version>1.2.0.RELEASE</version>
</dependency>複製代碼

狀態和事件

如今,我以用戶註冊爲案例,來說解狀態和事件之間的狀態機機制。github

狀態枚舉

註冊有哪些狀態呢,咱們來想一想,應該有4個狀態:未鏈接、已鏈接、註冊中、已註冊。spring

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 狀態機功能。springboot

初始化狀態機狀態

咱們須要初始化狀態機的狀態。微信

@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)) 定義了定義狀態機中存在的全部狀態。ide

初始化狀態遷移事件

咱們須要初始化當前狀態機有哪些狀態事件。ui

@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

(完)

更多精彩文章,盡在「服務端思惟」微信公衆號!

相關文章
相關標籤/搜索