蜗牛大师

吴庆龙的学习笔记

导航

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());
    }

}

posted on 2019-12-31 10:27  蜗牛大师  阅读(6525)  评论(0编辑  收藏  举报