Spring StateMachine 使用小結
一、基本概念
狀態(tài)機(State Machine) 是一種行為模型,定義了一組狀態(tài)、狀態(tài)之間的轉換(事件驅動)、以及在狀態(tài)轉換時觸發(fā)的動作。Spring StateMachine 提供了強大的框架支持,幫助開發(fā)者管理和驅動復雜的狀態(tài)流。
核心要素:
- State(狀態(tài)):對象所處的不同階段。
- Event(事件):觸發(fā)狀態(tài)轉換的動作。
- Transition(轉換):狀態(tài)之間的轉換過程。
- Action(動作):狀態(tài)轉換時執(zhí)行的業(yè)務邏輯。
二、核心組件
- StateMachine:狀態(tài)機核心接口,負責狀態(tài)管理和事件驅動。
- StateMachineConfigurerAdapter:狀態(tài)機配置適配器,用戶自定義狀態(tài)、事件、轉換邏輯。
- StateMachineFactory:狀態(tài)機工廠,創(chuàng)建狀態(tài)機實例。
- Actions:狀態(tài)轉換時執(zhí)行的具體業(yè)務邏輯。
- Guards:轉換前的條件判斷。
三、引入依賴
<!-- 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)機
通過繼承 StateMachineConfigurerAdapter 進行配置:
@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)機
注入并驅動狀態(tài)機:
@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í)行相關業(yè)務邏輯");
};
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions
.withExternal()
.source(OrderStates.CREATED).target(OrderStates.PAID).event(OrderEvents.PAY)
.action(payAction())
// 其他轉換...
}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())
// 其他轉換...
}八、持久化狀態(tài)機(可選)
Spring StateMachine 支持狀態(tài)持久化,可用 Redis、JPA 等存儲狀態(tài),適合分布式場景。
九、最佳實踐
- 合理拆分狀態(tài)與事件,避免過于復雜的狀態(tài)流。
- 利用動作和條件,實現業(yè)務與狀態(tài)解耦。
- 持久化狀態(tài)機,保證高可用和一致性。
- 結合 @WithStateMachine 注解,方便事件監(jiān)聽與回調。
十一、進階用法
1. 狀態(tài)監(jiān)聽器(StateMachineListener)
可以通過監(jiān)聽器獲取狀態(tài)變化、事件處理、異常等回調:
@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)機嵌套(子狀態(tài)機)
Spring StateMachine 支持嵌套狀態(tài)(Hierarchical States),適合復雜流程。
@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)機持久化
以 Redis 為例,持久化狀態(tài)機:
@Bean
public StateMachinePersister<OrderStates, OrderEvents, String> persister(
RedisStateMachinePersister<OrderStates, OrderEvents> persister) {
return persister;
}
// 保存狀態(tài)
persister.persist(stateMachine, "orderId-123");
// 恢復狀態(tài)
persister.restore(stateMachine, "orderId-123");4. 多實例狀態(tài)機
對于每個業(yè)務對象(如訂單),建議為每個對象創(chuàng)建獨立的狀態(tài)機實例:
@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. 結合Spring事件機制
可以通過監(jiān)聽 StateMachineEvent,實現解耦的業(yè)務響應。
十二、常見問題
狀態(tài)未切換?
- 檢查事件是否正確發(fā)送,狀態(tài)機是否
start(),Guard 是否返回 true。
- 檢查事件是否正確發(fā)送,狀態(tài)機是否
狀態(tài)機線程安全?
- 默認是線程不安全的,業(yè)務并發(fā)場景下請為每個業(yè)務對象創(chuàng)建獨立狀態(tài)機實例。
如何調試?
- 打開日志:
logging.level.org.springframework.statemachine=DEBUG,方便追蹤狀態(tài)流轉。
- 打開日志:
如何與數據庫結合?
- 利用持久化接口,將狀態(tài)機狀態(tài)存入數據庫,保證分布式一致性。
十三、實戰(zhàn)建議
- 不要把所有業(yè)務邏輯都塞到 Action,只做與狀態(tài)相關的處理,復雜邏輯建議外部調用。
- 事件驅動:外部只需發(fā)事件,狀態(tài)機自動處理后續(xù)流轉。
- 解耦:狀態(tài)機只關注流程和狀態(tài),業(yè)務邏輯在合適的位置實現。
- 測試:多寫單元測試,覆蓋各個狀態(tài)和異常流轉。
十四、完整示例
1. 配置類
@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStates, OrderEvents> {
// 狀態(tài)、事件、轉移配置同上
}2. 業(yè)務調用
@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);
}到此這篇關于Spring StateMachine 使用小結的文章就介紹到這了,更多相關Spring StateMachine 使用內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot 配置文件配置項前綴為0的數字特殊處理方式
這篇文章主要介紹了springboot 配置文件配置項前綴為0的數字特殊處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02
使用java?-jar修改SpringBoot中application.properties的配置項
這篇文章主要介紹了使用java?-jar修改SpringBoot中application.properties的配置項問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02

