StateMachine 狀態(tài)機(jī)機(jī)制深入解析
前言
Spring StateMachine 讓狀態(tài)機(jī)結(jié)構(gòu)更加層次化,可以幫助開發(fā)者簡化狀態(tài)機(jī)的開發(fā)過程。
之前,我們使用二維數(shù)組實(shí)現(xiàn)狀態(tài)機(jī)機(jī)制,現(xiàn)在,我們來用 Spring StateMachine 進(jìn)行改造。
環(huán)境依賴
修改 POM 文件,添加 spring-statemachine-core 依賴。
<dependency> <groupId>org.springframework.statemachine</groupId> <artifactId>spring-statemachine-core</artifactId> <version>1.2.0.RELEASE</version> </dependency>
狀態(tài)和事件
現(xiàn)在,我以用戶注冊為案例,來講解狀態(tài)和事件之間的狀態(tài)機(jī)機(jī)制。
狀態(tài)枚舉
注冊有哪些狀態(tài)呢,我們來想想,應(yīng)該有4個狀態(tài):未連接、已連接、注冊中、已注冊。
public enum RegStatusEnum {
// 未連接
UNCONNECTED,
// 已連接
CONNECTED,
// 注冊中
REGISTERING,
// 已注冊
REGISTERED;
}
事件枚舉
相對應(yīng)的,存在幾個核心事件:連接、注冊、注冊成功、注冊失敗、注銷。
public enum RegEventEnum {
// 連接
CONNECT,
// 注冊
REGISTER,
// 注冊成功
REGISTER_SUCCESS,
// 注冊失敗
REGISTER_FAILED,
// 注銷
UN_REGISTER;
}
狀態(tài)機(jī)配置
@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<RegStatusEnum, RegEventEnum> {
}
@EnableStateMachine注解,標(biāo)識啟用 Spring StateMachine 狀態(tài)機(jī)功能。
初始化狀態(tài)機(jī)狀態(tài)
我們需要初始化狀態(tài)機(jī)的狀態(tài)。
@Override
public void configure(StateMachineStateConfigurer<RegStatusEnum, RegEventEnum> states) throws Exception {
states.withStates()
// 定義初始狀態(tài)
.initial(RegStatusEnum.UNCONNECTED)
// 定義狀態(tài)機(jī)狀態(tài)
.states(EnumSet.allOf(RegStatusEnum.class));
}
其中,initial(RegStatusEnum.UNCONNECTED) 定義了初始狀態(tài)是未連接狀態(tài)。states(EnumSet.allOf(RegStatusEnum.class)) 定義了定義狀態(tài)機(jī)中存在的所有狀態(tài)。
初始化狀態(tài)遷移事件
我們需要初始化當(dāng)前狀態(tài)機(jī)有哪些狀態(tài)事件。
@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 指定原始狀態(tài),target 指定目標(biāo)狀態(tài),event 指定觸發(fā)事件。
因此,下面的狀態(tài)就很好理解了,即當(dāng)發(fā)生連接事件時(shí),從未連接狀態(tài)變更為已連接狀態(tài)。
// 未連接 -> 已連接 .withExternal() .source(RegStatusEnum.UNCONNECTED) .target(RegStatusEnum.CONNECTED) .event(RegEventEnum.CONNECT)
狀態(tài)監(jiān)聽器
Spring StateMachine 提供了注解配置實(shí)現(xiàn)方式,所有 StateMachineListener 接口中定義的事件都能通過注解的方式來進(jìn)行配置實(shí)現(xiàn)。
@WithStateMachine
public class StateMachineEventConfig {
@OnTransition(source = "UNCONNECTED", target = "CONNECTED")
public void connect() {
System.out.println("http:///////////////////");
System.out.println("連接事件, 未連接 -> 已連接");
System.out.println("http:///////////////////");
}
@OnTransition(source = "CONNECTED", target = "REGISTERING")
public void register() {
System.out.println("http:///////////////////");
System.out.println("注冊事件, 已連接 -> 注冊中");
System.out.println("http:///////////////////");
}
@OnTransition(source = "REGISTERING", target = "REGISTERED")
public void registerSuccess() {
System.out.println("http:///////////////////");
System.out.println("注冊成功事件, 注冊中 -> 已注冊");
System.out.println("http:///////////////////");
}
@OnTransition(source = "REGISTERED", target = "UNCONNECTED")
public void unRegister() {
System.out.println("http:///////////////////");
System.out.println("注銷事件, 已注冊 -> 未連接");
System.out.println("http:///////////////////");
}
}
這里,我仍然以連接事件為案例,@OnTransition 中 source 指定原始狀態(tài),target 指定目標(biāo)狀態(tài),當(dāng)事件觸發(fā)時(shí)將會被監(jiān)聽到從而調(diào)用 connect() 方法。
總結(jié)
Spring StateMachine 讓狀態(tài)機(jī)結(jié)構(gòu)更加層次化,可以幫助開發(fā)者簡化狀態(tài)機(jī)的開發(fā)過程。
我們來回顧下幾個核心步驟
- 定義狀態(tài)枚舉。
- 定義事件枚舉。
- 定義狀態(tài)機(jī)配置,設(shè)置初始狀態(tài),以及狀態(tài)與事件之間的關(guān)系。
- 定義狀態(tài)監(jiān)聽器,當(dāng)狀態(tài)變更時(shí),觸發(fā)方法。
源代碼
相關(guān)示例完整代碼: springboot-action
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java dom4j創(chuàng)建解析xml文檔過程解析
這篇文章主要介紹了Java dom4j創(chuàng)建解析xml文檔過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
關(guān)于HttpServletRequest獲取POST請求Body參數(shù)的3種方式
這篇文章主要介紹了關(guān)于HttpServletRequest獲取POST請求Body參數(shù)的3種方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Spring Boot基礎(chǔ)學(xué)習(xí)之Mybatis操作中使用Redis做緩存詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot基礎(chǔ)學(xué)習(xí)之Mybatis操作中使用Redis做緩存的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧2018-11-11
詳解MyBatis延遲加載是如何實(shí)現(xiàn)的
MyBatis 的延遲加載(懶加載)特性允許在需要使用關(guān)聯(lián)對象數(shù)據(jù)時(shí)才進(jìn)行加載,而不是在執(zhí)行主查詢時(shí)就加載所有相關(guān)數(shù)據(jù),我們將通過以下幾個方面來深入了解MyBatis的延遲加載實(shí)現(xiàn)機(jī)制,需要的朋友可以參考下2024-07-07

