Spring Statemachine 狀態(tài)機(jī)詳解
Spring Statemachine 詳解
Spring Statemachine 是一個(gè)強(qiáng)大的狀態(tài)機(jī)框架,用于在 Spring 應(yīng)用中實(shí)現(xiàn)復(fù)雜的狀態(tài)轉(zhuǎn)換邏輯。它特別適合管理具有多種狀態(tài)和轉(zhuǎn)換的業(yè)務(wù)流程,如訂單系統(tǒng)、工作流引擎、設(shè)備控制等。
一、核心概念
1. 狀態(tài)機(jī)基本元素
- 狀態(tài)(State):系統(tǒng)所處的特定條件
- 事件(Event):觸發(fā)狀態(tài)轉(zhuǎn)換的動(dòng)作
- 轉(zhuǎn)換(Transition):狀態(tài)之間的遷移
- 守衛(wèi)(Guard):轉(zhuǎn)換的條件判斷
- 動(dòng)作(Action):狀態(tài)轉(zhuǎn)換時(shí)執(zhí)行的業(yè)務(wù)邏輯
2. 狀態(tài)類型
- 初始狀態(tài)(Initial State):狀態(tài)機(jī)的起點(diǎn)
- 結(jié)束狀態(tài)(End State):狀態(tài)機(jī)的終點(diǎn)
- 普通狀態(tài)(Normal State):常規(guī)狀態(tài)
- 選擇狀態(tài)(Choice State):基于條件的分支
- 叉狀態(tài)(Fork State):并行執(zhí)行分支
- 連接狀態(tài)(Join State):合并并行分支
- 歷史狀態(tài)(History State):記錄并恢復(fù)之前狀態(tài)
二、依賴配置
Maven 依賴
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>3.2.0</version>
</dependency>Gradle 依賴
implementation 'org.springframework.statemachine:spring-statemachine-core:3.2.0'
三、基礎(chǔ)配置
1. 定義狀態(tài)和事件枚舉
public enum States {
SI, // 初始狀態(tài)
S1,
S2,
SF // 最終狀態(tài)
}
public enum Events {
E1,
E2
}2. 配置狀態(tài)機(jī)
@Configuration
@EnableStateMachine
public class StateMachineConfig
extends EnumStateMachineConfigurerAdapter<States, Events> {
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.states(EnumSet.allOf(States.class))
.end(States.SF);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withExternal()
.source(States.SI)
.target(States.S1)
.event(Events.E1)
.and()
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E2);
}
}四、高級(jí)特性
1. 守衛(wèi)(Guard)實(shí)現(xiàn)條件轉(zhuǎn)換
public class MyGuard implements Guard<States, Events> {
@Override
public boolean evaluate(StateContext<States, Events> context) {
// 檢查轉(zhuǎn)換條件
return context.getMessageHeader("key") != null;
}
}
// 在配置中添加守衛(wèi)
transitions
.withExternal()
.source(States.S1)
.target(States.S2)
.event(Events.E2)
.guard(new MyGuard());2. 動(dòng)作(Action)執(zhí)行業(yè)務(wù)邏輯
public class MyAction implements Action<States, Events> {
@Override
public void execute(StateContext<States, Events> context) {
// 執(zhí)行狀態(tài)轉(zhuǎn)換時(shí)的業(yè)務(wù)邏輯
System.out.println("Transition action executed");
}
}
// 在配置中添加動(dòng)作
transitions
.withExternal()
.source(States.SI)
.target(States.S1)
.event(Events.E1)
.action(new MyAction());3. 層次狀態(tài)(Hierarchical States)
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.state(States.S1)
.and()
.withStates()
.parent(States.S1)
.initial(States.S11)
.state(States.S12);
}4. 并行狀態(tài)(Fork/Join)
@Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.SI)
.fork(States.SFORK)
.join(States.SJOIN)
.and()
.withStates()
.parent(States.SFORK)
.initial(States.S1)
.end(States.S1END)
.and()
.withStates()
.parent(States.SFORK)
.initial(States.S2)
.end(States.S2END);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions)
throws Exception {
transitions
.withFork()
.source(States.SFORK)
.target(States.S1)
.target(States.S2)
.and()
.withJoin()
.source(States.S1END)
.source(States.S2END)
.target(States.SJOIN);
}5. 狀態(tài)機(jī)監(jiān)聽器
@Component
public class StateMachineListener
extends StateMachineListenerAdapter<States, Events> {
@Override
public void stateChanged(State<States, Events> from, State<States, Events> to) {
System.out.println("State changed from " + from + " to " + to);
}
@Override
public void eventNotAccepted(Message<Events> event) {
System.err.println("Event not accepted: " + event.getPayload());
}
}五、持久化狀態(tài)機(jī)
1. 配置持久化倉庫
@Bean
public StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister() {
return new JpaStateMachineRuntimePersister<>();
}2. 啟用持久化
@Configuration
@EnableStateMachineFactory
public class PersistConfig
extends StateMachineConfigurerAdapter<States, Events> {
@Autowired
private StateMachineRuntimePersister<States, Events, String> stateMachineRuntimePersister;
@Override
public void configure(StateMachineConfigurationConfigurer<States, Events> config)
throws Exception {
config
.withPersistence()
.runtimePersister(stateMachineRuntimePersister);
}
}3. 保存和恢復(fù)狀態(tài)
// 保存狀態(tài)
stateMachinePersist.persist(stateMachine, "machineId");
// 恢復(fù)狀態(tài)
StateMachine<States, Events> stateMachine =
stateMachineFactory.getStateMachine("machineId");
stateMachinePersist.restore(stateMachine, "machineId");六、狀態(tài)機(jī)可視化
1. 導(dǎo)出UML狀態(tài)圖
UmlStateMachineModelProducer modelProducer = new UmlStateMachineModelProducer(); Model model = modelProducer.produce(stateMachine.getStateMachineModel()); UmlStateMachineModelConverter converter = new UmlStateMachineModelConverter(); String uml = converter.convertToString(model); System.out.println(uml);
2. 生成PlantUML圖
@startuml [*] --> SI SI --> S1 : E1 S1 --> S2 : E2 S2 --> SF : E3 SF --> [*] @enduml
七、完整示例:訂單狀態(tài)機(jī)
1. 定義狀態(tài)和事件
public enum OrderStates {
CREATED, // 訂單創(chuàng)建
PAYMENT_PENDING, // 待支付
PAYMENT_RECEIVED,// 已支付
PROCESSING, // 處理中
SHIPPED, // 已發(fā)貨
DELIVERED, // 已送達(dá)
CANCELLED, // 已取消
RETURNED // 已退貨
}
public enum OrderEvents {
INITIATE_PAYMENT, // 發(fā)起支付
PAYMENT_SUCCESS, // 支付成功
PAYMENT_FAILED, // 支付失敗
PROCESS_ORDER, // 處理訂單
SHIP_ORDER, // 發(fā)貨
DELIVER_ORDER, // 送達(dá)
CANCEL_ORDER, // 取消訂單
RETURN_ORDER // 退貨
}2. 配置狀態(tài)機(jī)
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig
extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
throws Exception {
states
.withStates()
.initial(OrderStates.CREATED)
.state(OrderStates.PAYMENT_PENDING)
.state(OrderStates.PAYMENT_RECEIVED)
.state(OrderStates.PROCESSING)
.state(OrderStates.SHIPPED)
.state(OrderStates.DELIVERED)
.end(OrderStates.CANCELLED)
.end(OrderStates.RETURNED);
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
throws Exception {
transitions
// 從創(chuàng)建到待支付
.withExternal()
.source(OrderStates.CREATED)
.target(OrderStates.PAYMENT_PENDING)
.event(OrderEvents.INITIATE_PAYMENT)
.and()
// 支付成功
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.PAYMENT_RECEIVED)
.event(OrderEvents.PAYMENT_SUCCESS)
.and()
// 支付失敗
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.CANCELLED)
.event(OrderEvents.PAYMENT_FAILED)
.and()
// 開始處理訂單
.withExternal()
.source(OrderStates.PAYMENT_RECEIVED)
.target(OrderStates.PROCESSING)
.event(OrderEvents.PROCESS_ORDER)
.and()
// 發(fā)貨
.withExternal()
.source(OrderStates.PROCESSING)
.target(OrderStates.SHIPPED)
.event(OrderEvents.SHIP_ORDER)
.and()
// 送達(dá)
.withExternal()
.source(OrderStates.SHIPPED)
.target(OrderStates.DELIVERED)
.event(OrderEvents.DELIVER_ORDER)
.and()
// 取消訂單(在特定狀態(tài)下)
.withExternal()
.source(OrderStates.CREATED)
.target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL_ORDER)
.and()
.withExternal()
.source(OrderStates.PAYMENT_PENDING)
.target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL_ORDER)
.and()
// 退貨
.withExternal()
.source(OrderStates.DELIVERED)
.target(OrderStates.RETURNED)
.event(OrderEvents.RETURN_ORDER);
}
}3. 使用狀態(tài)機(jī)服務(wù)
@Service
public class OrderService {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
private final Map<Long, StateMachine<OrderStates, OrderEvents>> machines =
new ConcurrentHashMap<>();
public void createOrder(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = buildStateMachine(orderId);
sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
}
public void processPayment(Long orderId, boolean success) {
StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
if (sm != null) {
sm.sendEvent(success ?
OrderEvents.PAYMENT_SUCCESS :
OrderEvents.PAYMENT_FAILED);
}
}
public void shipOrder(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = machines.get(orderId);
if (sm != null && sm.getState().getId() == OrderStates.PROCESSING) {
sm.sendEvent(OrderEvents.SHIP_ORDER);
}
}
private StateMachine<OrderStates, OrderEvents> buildStateMachine(Long orderId) {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
sm.start();
machines.put(orderId, sm);
return sm;
}
}八、最佳實(shí)踐
1. 狀態(tài)機(jī)設(shè)計(jì)原則
- 保持狀態(tài)簡(jiǎn)單:每個(gè)狀態(tài)應(yīng)有明確的含義
- 限制狀態(tài)數(shù)量:避免狀態(tài)爆炸(State Explosion)
- 使用層次狀態(tài):管理復(fù)雜狀態(tài)關(guān)系
- 合理使用守衛(wèi):確保轉(zhuǎn)換條件清晰
- 分離業(yè)務(wù)邏輯:動(dòng)作應(yīng)調(diào)用服務(wù)而非包含復(fù)雜邏輯
2. 性能優(yōu)化
- 重用狀態(tài)機(jī)實(shí)例:避免頻繁創(chuàng)建
- 異步事件處理:使用
sendEvent(Message)異步接口 - 合理持久化:只在必要時(shí)持久化狀態(tài)
- 緩存守衛(wèi)結(jié)果:避免重復(fù)計(jì)算
3. 錯(cuò)誤處理
@Component
public class ErrorStateMachineListener
extends StateMachineListenerAdapter<OrderStates, OrderEvents> {
@Override
public void stateMachineError(
StateMachine<OrderStates, OrderEvents> stateMachine,
Exception exception) {
// 記錄錯(cuò)誤并處理
System.err.println("State machine error: " + exception.getMessage());
stateMachine.stop();
}
@Override
public void eventNotAccepted(Message<OrderEvents> event) {
// 處理不被接受的事件
System.err.println("Event not accepted: " + event.getPayload());
}
}九、測(cè)試狀態(tài)機(jī)
JUnit 測(cè)試示例
@SpringBootTest
public class OrderStateMachineTest {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
@Test
public void testOrderFlow() {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine();
sm.start();
// 初始狀態(tài)應(yīng)為CREATED
assertEquals(OrderStates.CREATED, sm.getState().getId());
// 發(fā)起支付
sm.sendEvent(OrderEvents.INITIATE_PAYMENT);
assertEquals(OrderStates.PAYMENT_PENDING, sm.getState().getId());
// 支付成功
sm.sendEvent(OrderEvents.PAYMENT_SUCCESS);
assertEquals(OrderStates.PAYMENT_RECEIVED, sm.getState().getId());
// 處理訂單
sm.sendEvent(OrderEvents.PROCESS_ORDER);
assertEquals(OrderStates.PROCESSING, sm.getState().getId());
// 發(fā)貨
sm.sendEvent(OrderEvents.SHIP_ORDER);
assertEquals(OrderStates.SHIPPED, sm.getState().getId());
// 送達(dá)
sm.sendEvent(OrderEvents.DELIVER_ORDER);
assertEquals(OrderStates.DELIVERED, sm.getState().getId());
}
}十、常見問題解決
1. 事件未被處理
- 檢查狀態(tài):確保當(dāng)前狀態(tài)支持該事件
- 驗(yàn)證守衛(wèi):檢查守衛(wèi)條件是否滿足
- 查看日志:?jiǎn)⒂肈EBUG日志查看狀態(tài)機(jī)內(nèi)部處理
2. 狀態(tài)機(jī)不啟動(dòng)
- 檢查配置:確保
@EnableStateMachine或@EnableStateMachineFactory已啟用 - 手動(dòng)啟動(dòng):調(diào)用
stateMachine.start() - 驗(yàn)證依賴:確保所有必需依賴已正確配置
3. 并發(fā)問題
- 使用同步:對(duì)狀態(tài)機(jī)操作加鎖
- 消息隊(duì)列:使用消息隊(duì)列順序處理事件
- 狀態(tài)機(jī)池:創(chuàng)建狀態(tài)機(jī)實(shí)例池
4. 持久化失敗
- 檢查序列化:確保狀態(tài)和事件可序列化
- 數(shù)據(jù)庫配置:驗(yàn)證持久化倉庫配置正確
- 事務(wù)管理:確保在事務(wù)邊界內(nèi)操作狀態(tài)機(jī)
Spring Statemachine 提供了強(qiáng)大的狀態(tài)管理能力,特別適合處理復(fù)雜的業(yè)務(wù)流程。通過合理設(shè)計(jì)狀態(tài)模型、轉(zhuǎn)換規(guī)則和業(yè)務(wù)動(dòng)作,可以構(gòu)建出高度可維護(hù)和可擴(kuò)展的狀態(tài)驅(qū)動(dòng)應(yīng)用。
到此這篇關(guān)于Spring Statemachine 狀態(tài)機(jī)詳解的文章就介紹到這了,更多相關(guān)Spring Statemachine 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 刪除數(shù)組元素與刪除重復(fù)數(shù)組元素的代碼
在java中刪除數(shù)組元素與過濾重復(fù)數(shù)組元素我們都會(huì)需要去遍歷數(shù)組然后根據(jù)我們?cè)O(shè)置的值或方法進(jìn)行去除數(shù)組2013-10-10
Java項(xiàng)目防止SQL注入的幾種方法總結(jié)
SQL注入是比較常見的網(wǎng)絡(luò)攻擊方式之一,在客戶端在向服務(wù)器發(fā)送請(qǐng)求的時(shí)候,sql命令通過表單提交或者url字符串拼接傳遞到后臺(tái)持久層,最終達(dá)到欺騙服務(wù)器執(zhí)行惡意的SQL命令,下面這篇文章主要給大家總結(jié)介紹了關(guān)于Java項(xiàng)目防止SQL注入的幾種方法,需要的朋友可以參考下2023-04-04
java?AES加密/解密實(shí)現(xiàn)完整代碼(附帶源碼)
這篇文章主要介紹了java?AES加密/解密實(shí)現(xiàn)的相關(guān)資料,包括AES加密算法的基本原理、Java加密API的使用方法以及項(xiàng)目實(shí)現(xiàn)的步驟和代碼示例,需要的朋友可以參考下2025-04-04
Mybatis-plus常見的坑@TableField不生效問題
這篇文章主要介紹了Mybatis-plus常見的坑@TableField不生效問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Java數(shù)據(jù)結(jié)構(gòu)順序表的詳細(xì)講解
大家好,今天給大家?guī)淼氖琼樞虮?,我覺得順序表還是有比較難理解的地方的,于是我就把這一塊的內(nèi)容全部整理到了一起,希望能夠給剛剛進(jìn)行學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的人帶來一些幫助,或者是已經(jīng)學(xué)過這塊的朋友們帶來更深的理解,我們現(xiàn)在就開始吧2022-05-05

