欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring狀態(tài)機(jī) Statemachine使用小結(jié)

 更新時(shí)間:2025年09月03日 10:05:55   作者:桂老七  
狀態(tài)機(jī)通過狀態(tài)、事件、配置管理流程,分離業(yè)務(wù)邏輯與狀態(tài)控制,實(shí)現(xiàn)結(jié)構(gòu)化流轉(zhuǎn),本文主要介紹了Spring狀態(tài)機(jī)Statemachine使用小結(jié),感興趣的可以了解一下

1. 狀態(tài)機(jī)簡介

狀態(tài)機(jī)(State Machine)是一種描述系統(tǒng)行為的數(shù)學(xué)模型,核心思想是將系統(tǒng)抽象為有限個(gè)狀態(tài),并通過狀態(tài)轉(zhuǎn)移規(guī)則定義系統(tǒng)如何響應(yīng)外部事件。它由一系列狀態(tài)(States)、轉(zhuǎn)換(Transitions)、事件(Events)、衛(wèi)兵(Guards)和動(dòng)作(Actions)組成。在軟件開發(fā)中,狀態(tài)機(jī)常用于控制程序的流程和狀態(tài)變化。

其核心優(yōu)勢在于: 通過清晰明確的狀態(tài)定義、自動(dòng)狀態(tài)更新,將復(fù)雜的狀態(tài)流轉(zhuǎn)邏輯結(jié)構(gòu)化。從而使得業(yè)務(wù)邏輯與狀態(tài)解耦,減少了自己維護(hù)狀態(tài)產(chǎn)生的大量if-else,顯著提升代碼可維護(hù)性和擴(kuò)展性??。

2. 核心組件介紹

2.1 流轉(zhuǎn)邏輯相關(guān):

組件?

處理邏輯類型?

State枚舉

枚舉對(duì)象所有的狀態(tài)(流程圖的節(jié)點(diǎn))

Events枚舉

枚舉所有引起兩個(gè)狀態(tài)之間切換的事件(流程圖的箭頭)

Configurer配置類

組裝State和Event的轉(zhuǎn)換關(guān)系 (相當(dāng)于流程圖)

StateMachine狀態(tài)機(jī)一個(gè)狀態(tài)機(jī)表征一個(gè)對(duì)象實(shí)體,它擁有狀態(tài),并通過event的驅(qū)動(dòng)來按照Configurer的配置進(jìn)行狀態(tài)變化,同時(shí)執(zhí)行配置中指定的guard、action和listener

2.2 業(yè)務(wù)邏輯組件:

(具體業(yè)務(wù)開發(fā)在這里寫,由框架負(fù)責(zé)調(diào)度)

組件?

處理邏輯類型?

是否阻塞遷移?

Guard?

純校驗(yàn)邏輯 (金額校驗(yàn)/渠道檢查)

是,失敗則中斷遷移

Action?

核心業(yè)務(wù)操作 (支付執(zhí)行/庫存扣減)

是,異常導(dǎo)致遷移失敗

Listener?

后續(xù)操作響應(yīng) (通知/日志/監(jiān)控)

否,異步執(zhí)行(也可同步)

2.3 流程示例圖

3. 示例代碼

3.1 依賴引入

<!--狀態(tài)機(jī)-->
<dependency>
	<groupId>org.springframework.statemachine</groupId>
	<artifactId>spring-statemachine-starter</artifactId>
	<version>3.2.0</version>
</dependency>

<!-- redis持久化狀態(tài)機(jī)--非必需組件,也可以用文件或數(shù)據(jù)庫做持久化 -->
<dependency>
	<groupId>org.springframework.statemachine</groupId>
	<artifactId>spring-statemachine-redis</artifactId>
	<version>1.2.9.RELEASE</version>
</dependency>

3.2 狀態(tài)枚舉定義

public enum OrderStatus {
    // 待支付,待發(fā)貨,待收貨,已完成
    WAIT_PAYMENT(1, "待支付"),
    WAIT_DELIVER(2, "待發(fā)貨"),
    WAIT_RECEIVE(3, "待收貨"),
    FINISH(4, "已完成");
    private Integer key;
    private String desc;
    OrderStatus(Integer key, String desc) {
        this.key = key;
        this.desc = desc;
    }
    public Integer getKey() {
        return key;
    }
    public String getDesc() {
        return desc;
    }
}

3.3 事件枚舉定義

public enum OrderStatusChangeEvent {
    // 支付,發(fā)貨,確認(rèn)收貨
    PAYED, DELIVERY, RECEIVED,UNPAY;
    /**
     * 獲取下一個(gè)事件枚舉
     *
     * @return 下一個(gè)事件枚舉
     */
    public OrderStatusChangeEvent getNextEvent() {
        switch (this) {
            case UNPAY:
                return PAYED;
            case PAYED:
                return DELIVERY;
            case DELIVERY:
                return RECEIVED;
            case RECEIVED:
                // 如果是最后一個(gè)事件,則返回null
                return null;
            default:
                // 如果枚舉值不在預(yù)期范圍內(nèi),則拋出異常
                throw new IllegalArgumentException("不支持的事件枚舉值");
        }
    }
}

3.4 配置類

@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderStatus, OrderStatusChangeEvent> {

    @Autowired
    private OrderGuard orderGuard;

    @Autowired
    private OrderAction orderAction;


    /**
     * 配置狀態(tài)
     *
     * @param states
     * @throws Exception
     */
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderStatusChangeEvent> states) throws Exception {
        states
                .withStates()
                .initial(OrderStatus.WAIT_PAYMENT)
                .states(EnumSet.allOf(OrderStatus.class));
    }
    /**
     * 配置狀態(tài)轉(zhuǎn)換事件關(guān)系
     *
     * @param transitions
     * @throws Exception
     */
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderStatusChangeEvent> transitions) throws Exception {
        transitions
                //支付事件:待支付-》待發(fā)貨
                .withExternal()
                .source(OrderStatus.WAIT_PAYMENT).target(OrderStatus.WAIT_DELIVER)
                .event(OrderStatusChangeEvent.PAYED)
                .guard(orderGuard)
                .action(orderAction)
                .and()
                //發(fā)貨事件:待發(fā)貨-》待收貨
                .withExternal()
                .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_RECEIVE)
                .event(OrderStatusChangeEvent.DELIVERY)
                .guard(orderGuard)
                .action(orderAction)
                .and()
                //收貨事件:待收貨-》已完成
                .withExternal()
                .source(OrderStatus.WAIT_RECEIVE).target(OrderStatus.FINISH)
                .event(OrderStatusChangeEvent.RECEIVED)
                .guard(orderGuard)
                .action(orderAction)
                .and()
                .withExternal()
                .source(OrderStatus.WAIT_DELIVER).target(OrderStatus.WAIT_PAYMENT)
                .event(OrderStatusChangeEvent.UNPAY)
                .guard(orderGuard)
                .action(orderAction);
    }
}

3.5 Guard--存放業(yè)務(wù)檢查邏輯

業(yè)務(wù)開發(fā)只用關(guān)心實(shí)現(xiàn)這個(gè)Guard接口不用關(guān)心執(zhí)行調(diào)度和狀態(tài)維護(hù)。

@Component
public class OrderGuard implements Guard<OrderStatus, OrderStatusChangeEvent> {
    @Override
    public boolean evaluate(StateContext<OrderStatus, OrderStatusChangeEvent> context) {
        Order order = context.getMessage().getHeaders().get("order", Order.class);
        // ...自定義業(yè)務(wù)檢查邏輯        
        return true;

    }
}

3.6 Action---存放業(yè)務(wù)執(zhí)行邏輯

業(yè)務(wù)開發(fā)只用關(guān)心實(shí)現(xiàn)這個(gè)Action接口不用關(guān)心執(zhí)行調(diào)度和狀態(tài)維護(hù)

@Slf4j
@Component
public class OrderAction implements Action<OrderStatus,OrderStatusChangeEvent> {

    @Resource
    private OrderMapper orderMapper;
    
    @Override
    public void execute(StateContext<OrderStatus, OrderStatusChangeEvent> stateContext) {
        try {
            Order order = stateContext.getMessage().getHeaders().get("order", Order.class);
            State<OrderStatus, OrderStatusChangeEvent> target = stateContext.getTarget();
            order.setStatus(target.getId().getKey());
            log.info("orderAction:{}", order);
            // 自定義業(yè)務(wù)執(zhí)行邏輯
            
        } catch (Exception e) {
            log.error("訂單狀態(tài)機(jī)執(zhí)行異常", e);
            stateContext.getStateMachine().setStateMachineError(new RuntimeException("自定義錯(cuò)誤"));
            throw e;
        }

    }
}

3.7 核心控制類

對(duì)并發(fā)有要求的使用工廠方法,每個(gè)訂單都單獨(dú)使用一個(gè)狀態(tài)機(jī)表達(dá)

@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private StateMachineFactory<OrderStatus, OrderStatusChangeEvent> stateMachineFactory;

    @Resource
    private StateMachinePersister<OrderStatus, OrderStatusChangeEvent, String> stateMachineRedisPersister;

    @Resource
    private OrderMapper orderMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    OrderStateListener orderStateListener;

    /**
     * 創(chuàng)建訂單
     *
     * @param order
     * @return
     */
    @DS("oracle-xxx")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Order create(Order order) {
        order.setStatus(OrderStatus.WAIT_PAYMENT.getKey());
        orderMapper.insert(order);
        return order;
    }
    /**
     * 對(duì)訂單進(jìn)行支付
     *
     * @param id
     * @return
     */
    @DS("oracle-xxx")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public boolean pay(Long id) {
        Order order = orderMapper.selectById(id);
        log.info("線程名稱:{},嘗試支付,訂單號(hào):{}" ,Thread.currentThread().getName() , id);
        return autoSendEvent(OrderStatusChangeEvent.PAYED, order);
    }
    

    /**
     * 發(fā)送訂單狀態(tài)轉(zhuǎn)換事件
     * synchronized修飾保證這個(gè)方法是線程安全的
     *
     * @param changeEvent
     * @param order
     * @return
     */
    private boolean sendEvent(OrderStatusChangeEvent changeEvent, Order order) {
        boolean result = false;
        StateMachine<OrderStatus, OrderStatusChangeEvent> orderStateMachine = null;
        try {
            // 工廠方法生成狀態(tài)機(jī)
            orderStateMachine = stateMachineFactory.getStateMachine(order.getId());
            orderStateMachine.addStateListener(orderStateListener);
            //啟動(dòng)狀態(tài)機(jī)
            orderStateMachine.start();
            //嘗試恢復(fù)狀態(tài)機(jī)狀態(tài)
            stateMachineRedisPersister.restore(orderStateMachine, String.valueOf(order.getId()));
            Message message = MessageBuilder.withPayload(changeEvent).setHeader("order", order).build();
            result = orderStateMachine.sendEvent(message);
            boolean hasError = orderStateMachine.hasStateMachineError();
            //持久化狀態(tài)機(jī)狀態(tài)
            if(hasError){
                return !hasError;
            }
            stateMachineRedisPersister.persist(orderStateMachine, String.valueOf(order.getId()));
            // 已結(jié)束的流程 給key加上過期時(shí)間
            if (order.getStatus() == OrderStatus.FINISH.getKey()) {
                redisUtil.set(order.getId(), order.getStatus(), 60 * 60 * 24, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error("訂單操作失敗:{}", e);
        } finally{
            if (orderStateMachine != null) {
                // 釋放狀態(tài)機(jī)
                orderStateMachine.stop();
            }
        }
        return result;
    }

    private boolean autoSendEvent(OrderStatusChangeEvent changeEvent, Order order) {
        boolean b = true;
        while (b && changeEvent != null) {
            b = sendEvent(changeEvent, order);
            changeEvent = changeEvent.getNextEvent();
        }
        return b;
    }
   

3.8 監(jiān)聽器

用來執(zhí)行一些不影響流程主流程的 日志、通知之類的任務(wù),可異步

@Component
@Slf4j
public class OrderStateListener extends StateMachineListenerAdapter<OrderStatus, OrderStatusChangeEvent> {


    private StateMachine<OrderStatus, OrderStatusChangeEvent> stateMachine;
    private Message<OrderStatusChangeEvent> message;


    @Override
    public void stateContext(StateContext<OrderStatus, OrderStatusChangeEvent> context) {
        
        StateMachine<OrderStatus, OrderStatusChangeEvent> stateMachine = context.getStateMachine();
        this.stateMachine = stateMachine;
        // 獲取當(dāng)前事件
        Message<OrderStatusChangeEvent> message = context.getMessage();
        this.message = message;

        // 獲取狀態(tài)機(jī) ID
        String machineId = stateMachine.getId();

        // 應(yīng)用場景:訂單狀態(tài)變更記錄
        if (context.getStage() == StateContext.Stage.STATE_CHANGED) {
            OrderStatus oldStatus = context.getSource().getId();
            OrderStatus newStatus = context.getTarget().getId();
            log.info("訂單 {} 狀態(tài)變更: {} → {}", machineId, oldStatus, newStatus);
        }

        if(context.getException()!=null){
            log.error("狀態(tài)機(jī)異常: {}",context.getException().getMessage());
        }
    }

    @DS("oracle-xxx")
    @Override
    public void stateChanged(State<OrderStatus, OrderStatusChangeEvent> from, State<OrderStatus, OrderStatusChangeEvent> to) {
        // 狀態(tài)變更時(shí)觸發(fā)(如 UNPAID → PAID)
        System.out.println("狀態(tài)變更: " + from.getId() + " → " + to.getId());
        Order order = message.getHeaders().get("order", Order.class);

        order.setStatus(to.getId().getKey());


    }

    @Override
    public void stateEntered(State<OrderStatus, OrderStatusChangeEvent> state) {
        // 進(jìn)入新狀態(tài)時(shí)觸發(fā)
        System.out.println("進(jìn)入狀態(tài): " + state.getId());
    }

    @Override
    @Async
    public void eventNotAccepted(Message<OrderStatusChangeEvent> message) {
        // 事件被拒絕時(shí)觸發(fā)(如非法狀態(tài)轉(zhuǎn)換)
        System.err.println("事件拒絕開始: " + message.getPayload());
        Order order = message.getHeaders().get("order", Order.class);
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.err.println("事件拒絕結(jié)束: " + message.getPayload());
    }

    @Override
    @Async
    public void stateMachineError(StateMachine<OrderStatus, OrderStatusChangeEvent> stateMachine, Exception exception) {
        // 只能建ring狀態(tài)機(jī)本身在運(yùn)行中發(fā)生的異常,不能處理action拋出的異常
        // 可以在此進(jìn)行重試、告警等操作
        log.error("錯(cuò)誤處理: {}", exception.getMessage());
    }

    @Override
    public void stateExited(State<OrderStatus, OrderStatusChangeEvent> state) {
        // 狀態(tài)機(jī)退出時(shí)觸發(fā)
        log.info("狀態(tài)退出: {}", state.getId());
    }


}

3.9 持久化

這里直接用的redis持久化,可自己定義成其他持久化方式

@Configuration
@Slf4j
public class Persist<E, S> {

    @Resource
    private RedisConnectionFactory redisConnectionFactory;
    /**
     * 持久化到redis中,在分布式系統(tǒng)中使用
     *
     * @return
     */
    @Bean(name = "stateMachineRedisPersister")
    public RedisStateMachinePersister<E, S> getRedisPersister() {
        RedisStateMachineContextRepository<E, S> repository = new RedisStateMachineContextRepository<>(redisConnectionFactory);
        RepositoryStateMachinePersist p = new RepositoryStateMachinePersist<>(repository);
        return new RedisStateMachinePersister<>(p);
    }
}

4. 總結(jié)

1. 狀態(tài)轉(zhuǎn)移通過配置類維護(hù),可讀性高,新增狀態(tài)時(shí)維護(hù)方便。

2. 狀態(tài)之間轉(zhuǎn)移通過由配置強(qiáng)制指定,不容易出現(xiàn)邏輯錯(cuò)亂。

3. 加鎖方便,可以在統(tǒng)一的事件觸發(fā)入口加redis分布式鎖。

4. 業(yè)務(wù)邏輯處理存放在Guard?、Action?、監(jiān)聽器中,各司其職結(jié)構(gòu)清晰,代碼邏輯解耦。

到此這篇關(guān)于Spring狀態(tài)機(jī) Statemachine使用小結(jié)的文章就介紹到這了,更多相關(guān)Spring狀態(tài)機(jī) Statemachine內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot中的Redis?緩存問題及操作方法

    SpringBoot中的Redis?緩存問題及操作方法

    這篇文章主要介紹了SpringBoot中的Redis?緩存,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • SpringCloud中的灰度路由使用詳解

    SpringCloud中的灰度路由使用詳解

    這篇文章主要介紹了SpringCloud中的灰度路由使用詳解,在微服務(wù)中,?通常為了高可用,?同一個(gè)服務(wù)往往采用集群方式部署,?即同時(shí)存在幾個(gè)相同的服務(wù),而灰度的核心就?是路由,?通過我們特定的策略去調(diào)用目標(biāo)服務(wù)線路,需要的朋友可以參考下
    2023-08-08
  • Spring事務(wù)傳播機(jī)制最佳實(shí)踐

    Spring事務(wù)傳播機(jī)制最佳實(shí)踐

    Spring的事務(wù)傳播機(jī)制為我們提供了優(yōu)雅的解決方案,本文將帶您深入理解這一機(jī)制,掌握不同場景下的最佳實(shí)踐,感興趣的朋友一起看看吧
    2025-07-07
  • java 優(yōu)雅關(guān)閉線程池的方案

    java 優(yōu)雅關(guān)閉線程池的方案

    這篇文章主要介紹了java 優(yōu)雅關(guān)閉線程池的方案,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-11-11
  • 關(guān)于SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過濾器的問題

    關(guān)于SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過濾器的問題

    這篇文章主要介紹了SpringBoot創(chuàng)建存儲(chǔ)令牌的媒介類和過濾器的問題,需要在配置文件中,添加JWT需要的密匙,過期時(shí)間和緩存過期時(shí)間,具體實(shí)例代碼參考下本文
    2021-09-09
  • 在Java中PDF與TIFF格式互轉(zhuǎn)的實(shí)現(xiàn)方案

    在Java中PDF與TIFF格式互轉(zhuǎn)的實(shí)現(xiàn)方案

    在IT行業(yè)中,處理圖像文件和文檔格式轉(zhuǎn)換是一項(xiàng)常見的任務(wù),本項(xiàng)目主要關(guān)注的是PDF與TIFF格式互轉(zhuǎn),TIFF是一種廣泛用于掃描儀和打印機(jī)的圖像文件格式,尤其適合存儲(chǔ)多頁的圖像,如傳真或文檔掃描,本文給大家介紹了Java中PDF與TIFF格式互轉(zhuǎn)的實(shí)現(xiàn)方案,需要的朋友可以參考下
    2025-06-06
  • spring?mvc?AOP切面方法未執(zhí)行的一種情況的分析和處理過程

    spring?mvc?AOP切面方法未執(zhí)行的一種情況的分析和處理過程

    這篇文章主要介紹了spring?mvc?AOP切面方法未執(zhí)行的一種情況的分析和處理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java利用策略模式實(shí)現(xiàn)條件判斷,告別if else

    Java利用策略模式實(shí)現(xiàn)條件判斷,告別if else

    策略模式定義了一系列算法,并且將每個(gè)算法封裝起來,使得他們可以相互替換,而且算法的變化不會(huì)影響使用算法的客戶端。本文將通過案例講解如何利用Java的策略模式實(shí)現(xiàn)條件判斷,告別if----else條件硬編碼,需要的可以參考一下
    2022-02-02
  • java string類的常用方法詳細(xì)介紹

    java string類的常用方法詳細(xì)介紹

    在開發(fā)過程中經(jīng)常會(huì)使用到j(luò)ava string類的方法,本文將以此問題進(jìn)行詳細(xì)介紹
    2012-11-11
  • Spring aop失效的幾種解決方案

    Spring aop失效的幾種解決方案

    這篇文章主要介紹了Spring aop失效的幾種解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05

最新評(píng)論