Squirrel(松鼠)狀態機的使用


概述

其實對於英文好的同學來說,這個狀態機的使用就非常簡單了,參考https://github.com/hekailiang/squirrel上的文檔即可,因為這個狀態機的入門成本並不高。

實戰代碼

由於這個狀態機比較簡單,就直接上代碼了,注釋寫在代碼里,通過調試運行,相信你馬上就理解了。

定義事件FSMEvent.java

/**
 * 定義狀態機事件
 *
 * @author: 吳慶龍
 * @date: 2019/12/23 10:44 上午
 */
public enum FSMEvent {
    ToA, ToB, ToC, ToD, toE, ToF
}

定義監聽器DeclarativeEventListener.java

import lombok.extern.slf4j.Slf4j;
import org.squirrelframework.foundation.exception.TransitionException;
import org.squirrelframework.foundation.fsm.Action;
import org.squirrelframework.foundation.fsm.annotation.*;

/**
 * 聲明式監聽
 *
 * @author: 吳慶龍
 * @date: 2019/12/23 1:20 下午
 */
@Slf4j
public class DeclarativeEventListener {

    /**
     * 轉換事件開始時進行調用
     */
    @OnTransitionBegin
    public void transitionBegin(FSMEvent event) {
        System.out.println();
        log.info("transitionBegin event {}", event);
    }

    /**
     * 轉換事件開始時進行調用
     * 可以加入條件
     * 'event'(E), 'from'(S), 'to'(S), 'context'(C) and 'stateMachine'(T) can be used in MVEL scripts
     */
    @OnTransitionBegin(when="event.name().equals(\"ToB\")")
    public void transitionBeginConditional() {
        log.info("transitionBeginConditional");
    }

    /**
     * 轉換事件結束時進行調用
     * 這個方法必須是 public 並且返回值是 void
     */
    @OnTransitionEnd
    @ListenerOrder(10)
    public void transitionEnd() {
        log.info("transitionEnd");
        System.out.println();
    }

    @OnTransitionComplete
    public void transitionComplete(String from, String to, FSMEvent event, Integer context) {
        log.info("transitionComplete {}=>{} on {} with {}", from, to, event, context);
    }

    @OnTransitionException
    public void transitionException(String from, String to, FSMEvent event, Integer context) {
        log.info("transitionException");
    }

    /**
     * 當轉換被拒絕時,將調用注有TransitionDecline的方法
     */
    @OnTransitionDecline
    public void transitionDeclined(String from, FSMEvent event, Integer context) {
        log.info("transitionDeclined {}=>??? on {} with {}", from, event, context);
    }

    /**
     * 帶有 OnAfterActionExecuted 注釋的方法將在調用操作之前被調用
     * 實際是 callMethod 中的方法被調用錢執行這個方法。類似於 AOP 的效果,運行一下即可知道
     */
    @OnBeforeActionExecuted
    public void onBeforeActionExecuted(Object sourceState, Object targetState,
                                       Object event, Object context, int[] mOfN, Action<?, ?, ?,?> action) {
        log.info("onBeforeActionExecuted");
    }

    /**
     * 帶有 OnAfterActionExecuted 注釋的方法將在調用操作之后被調用
     * 實際是 callMethod 中的方法被調用后執行這個方法。類似於 AOP 的效果,運行一下即可知道
     */
    @OnAfterActionExecuted
    public void onAfterActionExecuted(Object sourceState, Object targetState,
                                      Object event, Object context, int[] mOfN, Action<?, ?, ?,?> action) {
        log.info("onAfterActionExecuted");
    }

    /**
     * 帶有 OnActionExecException 注釋的方法將在調用操作異常之后被調用
     * 實際是 callMethod 中的方法被調用時拋異常了之后執行這個方法。類似於 AOP 的效果,運行一下即可知道
     */
    @OnActionExecException
    public void onActionExecException(Action<?, ?, ?,?> action, TransitionException e) {
        log.info("onActionExecException");
    }

}

狀態機和StateMachineSample.java

import lombok.extern.slf4j.Slf4j;
import org.squirrelframework.foundation.fsm.*;
import org.squirrelframework.foundation.fsm.annotation.StateMachineParameters;
import org.squirrelframework.foundation.fsm.impl.AbstractUntypedStateMachine;

/**
 * 定義狀態機,支持如下格式的方法定義
 * transitFrom[fromStateName]To[toStateName]On[eventName]When[conditionName]
 * transitFrom[fromStateName]To[toStateName]On[eventName]
 * transitFromAnyTo[toStateName]On[eventName]
 * transitFrom[fromStateName]ToAnyOn[eventName]
 * transitFrom[fromStateName]To[toStateName]
 * on[eventName]
 * entry[eventName]
 * exit[eventName]
 *
 * @author: 吳慶龍
 * @date: 2019/12/23 10:46 上午
 */
@Slf4j
@StateMachineParameters(stateType = String.class, eventType = FSMEvent.class, contextType = Integer.class)
public class StateMachineSample extends AbstractUntypedStateMachine {

    // =========== A -> B:需要將方法名配置在 callMethod 內
    public void fromAToB(String from, String to, FSMEvent event, Integer context) {
        log.info("轉換事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // =========== B -> C:符合 transitFrom[fromStateName]To[toStateName] 格式,不需要配置 callMethod
    public void transitFromBToC(String from, String to, FSMEvent event, Integer context) {
        log.info("轉換事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // =========== 進入 A, 符合 entry[StateName] 格式,不需要配置 callMethod
    public void entryA(String from, String to, FSMEvent event, Integer context) {
        log.info("進入事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // =========== 退出 A, 符合 exit[StateName] 格式,不需要配置 callMethod
    public void exitA(String from, String to, FSMEvent event, Integer context) {
        log.info("退出事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // =========== 進入 B
    public void enterB(String from, String to, FSMEvent event, Integer context) {
        log.info("進入事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // =========== 退出 B
    public void exitB(String from, String to, FSMEvent event, Integer context) {
        log.info("退出事件 {}=>{} on {} with {}.", from, to, event, context);
    }

    // ==========================================================================================
    // 如果不想用 DeclarativeEventListener 這種聲明在單獨類里的方法,可以直接重寫以下方法,效果是一樣的
    // 兩者同時用也可以,為了代碼方便最好別這樣
    // ==========================================================================================
    @Override
    protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {
//        super.afterTransitionCausedException(fromState, toState, event, context);
        // 默認的實現是直接拋異常
        log.info("Override 發生錯誤 {}", getLastException().getMessage());
    }
    @Override
    protected void beforeTransitionBegin(Object fromState, Object event, Object context) {
        // 轉換開始時被調用
        System.out.println();
        super.beforeTransitionBegin(fromState, event, context);
        log.info("Override beforeTransitionBegin");
    }
    @Override
    protected void afterTransitionCompleted(Object fromState, Object toState, Object event, Object context) {
        // 轉換完成時被調用
        super.afterTransitionCompleted(fromState, toState, event, context);
        log.info("Override afterTransitionCompleted");
    }
    @Override
    protected void afterTransitionEnd(Object fromState, Object toState, Object event, Object context) {
        // 轉換結束時被調用
        super.afterTransitionEnd(fromState, toState, event, context);
        log.info("Override afterTransitionEnd");
        System.out.println();
    }
    @Override
    protected void afterTransitionDeclined(Object fromState, Object event, Object context) {
        // 當轉換被拒絕時被調用。實際是調用 callMethod 中的方法被調用時,拋出異常時被調用
        super.afterTransitionDeclined(fromState, event, context);
        log.info("Override afterTransitionDeclined");
    }
    @Override
    protected void beforeActionInvoked(Object fromState, Object toState, Object event, Object context) {
        // 當轉換開始時被調用。實際是 callMethod 中的方法被調用時,類似於 AOP 的效果,運行一下即可知道
        super.beforeActionInvoked(fromState, toState, event, context);
        log.info("Override beforeActionInvoked");
    }
    @Override
    protected void afterActionInvoked(Object fromState, Object toState, Object event, Object context) {
        // 當轉換結束時被調用。實際是 callMethod 被調用時,類似於 AOP 的效果,運行一下即可知道
        super.afterActionInvoked(fromState, toState, event, context);
        log.info("Override afterActionInvoked");
    }


    public static void main(String[] args) {
        // 構造 builder
        StateMachineConfiguration stateMachineConfiguration = StateMachineConfiguration.create()
                .enableAutoStart(false);
        UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class);
        builder.setStateMachineConfiguration(stateMachineConfiguration);

        // 配置狀態流轉時觸發的事件
        builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB");
        builder.externalTransition().from("B").to("C").on(FSMEvent.ToC);
        builder.onEntry("A");
        builder.onExit("A");
        builder.onEntry("B").callMethod("enterB");
        builder.onExit("B");

        // 使用狀態機
        UntypedStateMachine fsm = builder.newStateMachine("A");
        fsm.start();

        // 添加監聽器
//        fsm.addStateMachineListener(new StateMachineListener<UntypedStateMachine, Object, Object, Object>() {
//            @Override
//            public void stateMachineEvent(StateMachineEvent<UntypedStateMachine, Object, Object, Object> event) {
//                log.info("lastState: " + event.getStateMachine().getLastState());
//            }
//        });
//        fsm.addDeclarativeListener(new DeclarativeEventListener());
        // 源碼中的日志 demo
//        StateMachineLogger logger = new StateMachineLogger(fsm);
//        logger.startLogging();

        fsm.fire(FSMEvent.ToB, 1);
        fsm.fire(FSMEvent.ToC);

        System.out.println("Current state is " + fsm.getCurrentState());
    }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM