Spring StateMachine 使用小結(jié)
一、基本概念
狀態(tài)機(jī)(State Machine) 是一種行為模型,定義了一組狀態(tài)、狀態(tài)之間的轉(zhuǎn)換(事件驅(qū)動)、以及在狀態(tài)轉(zhuǎn)換時觸發(fā)的動作。Spring StateMachine 提供了強(qiáng)大的框架支持,幫助開發(fā)者管理和驅(qū)動復(fù)雜的狀態(tài)流。
核心要素:
- State(狀態(tài)):對象所處的不同階段。
- Event(事件):觸發(fā)狀態(tài)轉(zhuǎn)換的動作。
- Transition(轉(zhuǎn)換):狀態(tài)之間的轉(zhuǎn)換過程。
- Action(動作):狀態(tài)轉(zhuǎn)換時執(zhí)行的業(yè)務(wù)邏輯。
二、核心組件
- StateMachine:狀態(tài)機(jī)核心接口,負(fù)責(zé)狀態(tài)管理和事件驅(qū)動。
- StateMachineConfigurerAdapter:狀態(tài)機(jī)配置適配器,用戶自定義狀態(tài)、事件、轉(zhuǎn)換邏輯。
- StateMachineFactory:狀態(tài)機(jī)工廠,創(chuàng)建狀態(tài)機(jī)實例。
- Actions:狀態(tài)轉(zhuǎn)換時執(zhí)行的具體業(yè)務(wù)邏輯。
- Guards:轉(zhuǎn)換前的條件判斷。
三、引入依賴
<!-- Maven依賴 -->
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>4.0.0</version>
</dependency>四、定義狀態(tài)和事件
以訂單流程為例:
public enum OrderStates {
CREATED, PAID, SHIPPED, COMPLETED, CANCELLED
}
public enum OrderEvents {
PAY, SHIP, COMPLETE, CANCEL
}五、配置狀態(tài)機(jī)
通過繼承 StateMachineConfigurerAdapter 進(jìn)行配置:
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
states
.withStates()
.initial(OrderStates.CREATED)
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions
.withExternal().source(OrderStates.CREATED).target(OrderStates.PAID).event(OrderEvents.PAY)
.and()
.withExternal().source(OrderStates.PAID).target(OrderStates.SHIPPED).event(OrderEvents.SHIP)
.and()
.withExternal().source(OrderStates.SHIPPED).target(OrderStates.COMPLETED).event(OrderEvents.COMPLETE)
.and()
.withExternal().source(OrderStates.CREATED).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL)
.and()
.withExternal().source(OrderStates.PAID).target(OrderStates.CANCELLED).event(OrderEvents.CANCEL);
}
}六、使用狀態(tài)機(jī)
注入并驅(qū)動狀態(tài)機(jī):
@Autowired
private StateMachine<OrderStates, OrderEvents> stateMachine;
public void processOrder() {
stateMachine.start();
stateMachine.sendEvent(OrderEvents.PAY);
stateMachine.sendEvent(OrderEvents.SHIP);
stateMachine.sendEvent(OrderEvents.COMPLETE);
}七、添加動作和條件
1. 動作(Action)
@Bean
public Action<OrderStates, OrderEvents> payAction() {
return context -> {
System.out.println("訂單已支付,執(zhí)行相關(guān)業(yè)務(wù)邏輯");
};
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions
.withExternal()
.source(OrderStates.CREATED).target(OrderStates.PAID).event(OrderEvents.PAY)
.action(payAction())
// 其他轉(zhuǎn)換...
}2. 條件(Guard)
@Bean
public Guard<OrderStates, OrderEvents> payGuard() {
return context -> {
// 只有金額大于0才能支付
Integer amount = (Integer) context.getMessageHeader("amount");
return amount != null && amount > 0;
};
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions
.withExternal()
.source(OrderStates.CREATED).target(OrderStates.PAID).event(OrderEvents.PAY)
.guard(payGuard())
// 其他轉(zhuǎn)換...
}八、持久化狀態(tài)機(jī)(可選)
Spring StateMachine 支持狀態(tài)持久化,可用 Redis、JPA 等存儲狀態(tài),適合分布式場景。
九、最佳實踐
- 合理拆分狀態(tài)與事件,避免過于復(fù)雜的狀態(tài)流。
- 利用動作和條件,實現(xiàn)業(yè)務(wù)與狀態(tài)解耦。
- 持久化狀態(tài)機(jī),保證高可用和一致性。
- 結(jié)合 @WithStateMachine 注解,方便事件監(jiān)聽與回調(diào)。
十一、進(jìn)階用法
1. 狀態(tài)監(jiān)聽器(StateMachineListener)
可以通過監(jiān)聽器獲取狀態(tài)變化、事件處理、異常等回調(diào):
@Component
public class OrderStateMachineListener extends StateMachineListenerAdapter<OrderStates, OrderEvents> {
@Override
public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
System.out.println("狀態(tài)從 " + (from == null ? "none" : from.getId()) + " 變?yōu)?" + to.getId());
}
@Override
public void eventNotAccepted(Message<OrderEvents> event) {
System.out.println("事件未被接受: " + event.getPayload());
}
}注冊監(jiān)聽器:
@Autowired
private StateMachine<OrderStates, OrderEvents> stateMachine;
@Autowired
private OrderStateMachineListener listener;
@PostConstruct
public void addListener() {
stateMachine.addStateListener(listener);
}2. 狀態(tài)機(jī)嵌套(子狀態(tài)機(jī))
Spring StateMachine 支持嵌套狀態(tài)(Hierarchical States),適合復(fù)雜流程。
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
states
.withStates()
.initial(OrderStates.CREATED)
.state(OrderStates.PAID)
.and()
.withStates()
.parent(OrderStates.PAID)
.initial(OrderStates.PAID_SUB1)
.state(OrderStates.PAID_SUB2);
}3. 狀態(tài)機(jī)持久化
以 Redis 為例,持久化狀態(tài)機(jī):
@Bean
public StateMachinePersister<OrderStates, OrderEvents, String> persister(
RedisStateMachinePersister<OrderStates, OrderEvents> persister) {
return persister;
}
// 保存狀態(tài)
persister.persist(stateMachine, "orderId-123");
// 恢復(fù)狀態(tài)
persister.restore(stateMachine, "orderId-123");4. 多實例狀態(tài)機(jī)
對于每個業(yè)務(wù)對象(如訂單),建議為每個對象創(chuàng)建獨立的狀態(tài)機(jī)實例:
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
public void handleOrder(String orderId) {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine(orderId);
sm.start();
sm.sendEvent(OrderEvents.PAY);
}5. 結(jié)合Spring事件機(jī)制
可以通過監(jiān)聽 StateMachineEvent,實現(xiàn)解耦的業(yè)務(wù)響應(yīng)。
十二、常見問題
狀態(tài)未切換?
- 檢查事件是否正確發(fā)送,狀態(tài)機(jī)是否
start(),Guard 是否返回 true。
- 檢查事件是否正確發(fā)送,狀態(tài)機(jī)是否
狀態(tài)機(jī)線程安全?
- 默認(rèn)是線程不安全的,業(yè)務(wù)并發(fā)場景下請為每個業(yè)務(wù)對象創(chuàng)建獨立狀態(tài)機(jī)實例。
如何調(diào)試?
- 打開日志:
logging.level.org.springframework.statemachine=DEBUG,方便追蹤狀態(tài)流轉(zhuǎn)。
- 打開日志:
如何與數(shù)據(jù)庫結(jié)合?
- 利用持久化接口,將狀態(tài)機(jī)狀態(tài)存入數(shù)據(jù)庫,保證分布式一致性。
十三、實戰(zhàn)建議
- 不要把所有業(yè)務(wù)邏輯都塞到 Action,只做與狀態(tài)相關(guān)的處理,復(fù)雜邏輯建議外部調(diào)用。
- 事件驅(qū)動:外部只需發(fā)事件,狀態(tài)機(jī)自動處理后續(xù)流轉(zhuǎn)。
- 解耦:狀態(tài)機(jī)只關(guān)注流程和狀態(tài),業(yè)務(wù)邏輯在合適的位置實現(xiàn)。
- 測試:多寫單元測試,覆蓋各個狀態(tài)和異常流轉(zhuǎn)。
十四、完整示例
1. 配置類
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
// 狀態(tài)、事件、轉(zhuǎn)移配置同上
}2. 業(yè)務(wù)調(diào)用
@Service
public class OrderService {
@Autowired
private StateMachineFactory<OrderStates, OrderEvents> factory;
public void payOrder(String orderId) {
StateMachine<OrderStates, OrderEvents> sm = factory.getStateMachine(orderId);
sm.start();
sm.sendEvent(OrderEvents.PAY);
// 可持久化 sm
}
}3. 持久化(可選)
@Autowired
private StateMachinePersister<OrderStates, OrderEvents, String> persister;
public void saveState(StateMachine<OrderStates, OrderEvents> sm, String orderId) throws Exception {
persister.persist(sm, orderId);
}
public void restoreState(StateMachine<OrderStates, OrderEvents> sm, String orderId) throws Exception {
persister.restore(sm, orderId);
}到此這篇關(guān)于Spring StateMachine 使用小結(jié)的文章就介紹到這了,更多相關(guān)Spring StateMachine 使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot 1.5.7整合Kafka-client代碼示例
這篇文章主要介紹了Springboot 1.5.7整合Kafka-client代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
解決阿里代碼規(guī)范檢測中方法缺少javadoc注釋的問題
這篇文章主要介紹了解決阿里代碼規(guī)范檢測中方法缺少javadoc注釋的問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Java的函數(shù)式接口@FunctionalInterface的使用說明
這篇文章主要介紹了Java的函數(shù)式接口@FunctionalInterface的使用說明,我們常用的一些接口Callable、Runnable、Comparator等在JDK8中都添加了@FunctionalInterface注解,需要的朋友可以參考下2024-01-01
Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法
這篇文章主要介紹了Java中FTPClient上傳中文目錄、中文文件名亂碼問題解決方法,本文使用apache-commons-net工具包時遇到這個問題,解決方法很簡單,需要的朋友可以參考下2015-05-05
java jdk1.8 使用stream流進(jìn)行l(wèi)ist 分組歸類操作
這篇文章主要介紹了java jdk1.8 使用stream流進(jìn)行l(wèi)ist 分組歸類操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10

