Squirrel(松鼠)状态机的介绍及使用

简介: Squirrel(松鼠)状态机的介绍及使用

概述

参考:squirrel-foundation状态机的使用细节

有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型

状态机可以描述核心业务规则,核心业务内容,总结一下就是 a 实体,在 b 状态下,由 c 角色,在满足 d 条件时,执行 e 操作成功后,迁移到f状态下,并产生 g 事件,通常用于业务复杂的订单等业务里。


生命周期

状态机创建过程

  • StateMachine

    StateMachine 实例由 StateMachineBuilder 创建不被共享

    对于使用 annotation 方式(或fluent api)定义的 StateMachine,StateMachine 实例即根据此定义创建,相应的 action 也由本实例执行,与 spring 的集成最终要的就是讲 spring 的 bean 实例注入给由 builder 创建的状态机实例;

  • StateMachineBuilder

    本质上是由 StateMachineBuilderFactory 创建的动态代理。

    被代理的 StateMachineBuilder 默认实现为 StateMachineBuilderImpl,内部描述了状态机实例创建细节包括 State、Event、Context 类型信息、constructor 等,同时也包含了 StateMachine 的一些全局共享资源包括 StateConverter、EventConverter、MvelScriptManage r等。StateMachineBuilder 可被复用,使用中可被实现为 singleton;

  • StateMachineBuilderFactory:为StateMachineBuilder创建的动态代理实例;


事件处理过程

  • 状态正常迁移

    TransitionBegin--(exit->transition->entry)-->TransitionComplete-->TransitionEnd

  • 状态迁移异常

    TransitionBegin--(exit->transition->entry)-->TransitionException-->TransitionEnd

  • 状态迁移事件拒绝

    TransitionBegin-->TransitionDeclined-->TransitionEnd

QQ截图20210417154259.png


状态持久化与事务

状态持久化

从 StateMachine 的事件响应流程中可以看到,TransitionBegin --(exit -> transition -> entry) --> TransitionComplete -->TransitionEnd,在 TransitionComplete 发生一个状态已从 source 迁移到了 target 状态,所以可以选择在这个时间点进行了状态的持久化(没有选择 TransitionEnd 做持久化,因为某些场景在持久化完成后还会存在一些外部动作的触发,例如通知第三方系统当前状态已完成变更)。代码详见声明式状态机TransitionComplete()方法。


分布式锁 + 事务

由于 StateMachine 实例不是由 Spring 容器创建,所以这个过程中无法通过注解方式开启事务(Spring没有机会去创建事务代理),采用了编程式事务,在 AbstractStateMachineEngine 的 fire 函数中隐式的实现(代码详见:声明式状态机AbstractStateMachineEngine#fire)


案例

依赖

<dependency>
    <groupId>org.squirrelframework</groupId>
    <artifactId>squirrel-foundation</artifactId>
    <version>0.3.8</version>
</dependency>


声明式无类型状态机

参考:

利用状态机模拟一个订单的支付过程

状态机引擎

/**
 * 创建无类型化状态机,简化状态机,防止过多泛化导致代码不易阅读
 * 通过Spring创建StateMachineBuilder实例,通过buidler创建状态机(单例)
 * 业务函数中通过StateMachineBuilder实例创建StateMachine实例,并向StateMachine暴露SpringApplicationContext,以便于StateMachine通过ApplicationContext获取数据层的对象
*/
@Slf4j
public class AbstractStateMachineEngine <T extends UntypedStateMachine> implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    protected UntypedStateMachineBuilder stateMachineBuilder = null;

    @SuppressWarnings("unchecked")
    public AbstractStateMachineEngine() {
        //识别泛型参数
        Class<T> genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(),
                AbstractStateMachineEngine.class);
        stateMachineBuilder = StateMachineBuilderFactory.create(genericType, ApplicationContext.class);
    }
    //注入applicationContext,并在创建StateMachine实例时注入
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
    *    可以通过向OrderContext 上下文传递一些业务参数,比如orderId等等
    */
    public boolean fire(EOrderEvents event, OrderContext context) {
        T stateMachine = stateMachineBuilder.newUntypedStateMachine(
                context.geteOrder().getOrderStatus(),applicationContext);
        
        // 添加监听器
//        stateMachine.addStateMachineListener(new StateMachineListener<UntypedStateMachine, Object, Object, Object>() {
//            @Override
//            public void stateMachineEvent(StateMachineEvent<UntypedStateMachine, Object, Object, Object> event) {
//                log.info("lastState: " + event.getStateMachine().getLastState());
//            }
//        });
//        stateMachine.addDeclarativeListener(new DeclarativeEventListener());
        // 源码中的日志 demo
//        StateMachineLogger logger = new StateMachineLogger(stateMachine);
//        logger.startLogging();
        
        //由于StateMachine实例不是由Spring容器创建,所以这个过程中无法通过注解方式开启事务(Spring没有机会去创建事务代理),因此采用了编程式事务
        DataSourceTransactionManager transactionManager = (DataSourceTransactionManager)applicationContext.getBean("transactionManager");
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            stateMachine.fire(event, context);
            transactionManager.commit(status);
            //这里会返回状态机是否出错,如果出错可用于通知Controller层
            return stateMachine.isError();
        } catch (Exception ex) {
            //用于事务回滚
            transactionManager.rollback(status);
            return true;
        }
    }
}

继承AbstractStateMachineEngine,并加入@Service注解,便可以在项目中注入。(单例)

@Service
public class OrderStateMachineEngine extends AbstractStateMachineEngine<SubmitOrderStateMachine>{

}


定义状态机(基于注解的方式)

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

/**
 * 定义 触发事件、状态变化时,调用的方法
 * @States 定义状态列表,里面可以包含多个状态
 * @State定义每个状态,name状态名称,entryStateInit进入状态时调用的方法,exitCallMethod 离开状态是调用的方法,initialState 为true时,为默认状态。
 * */
@States({
        @State(name = "INIT", entryCallMethod = "entryStateInit", exitCallMethod = "exitStateInit", initialState = true),
        @State(name = "WAIT_PAY", entryCallMethod = "entryStateWaitPay", exitCallMethod = "exitStateWaitPay"),
        @State(name = "WAIT_SEND", entryCallMethod = "entryStateWaitSend", exitCallMethod = "exitStateWaitSend"),
        @State(name = "PART_SEND", entryCallMethod = "entryStatePartSend", exitCallMethod = "exitStatePartSend"),
        @State(name = "WAIT_RECEIVE", entryCallMethod = "entryStateWaitReceive", exitCallMethod = "exitStateWaitReceive"),
        @State(name = "COMPLETE", entryCallMethod = "entryStateComplete", exitCallMethod = "exitStateComplete")
})
@Transitions({
        @Transit(from = "INIT", to = "WAIT_PAY", on = "SUBMIT_ORDER", callMethod = "submitOrder"),
        @Transit(from = "WAIT_PAY", to = "WAIT_SEND", on = "PAY", callMethod = "pay"),
        @Transit(from = "WAIT_SEND", to = "PART_SEND", on = "PART_SEND", callMethod = "partSend"),
        @Transit(from = "PART_SEND", to = "WAIT_RECEIVE", on = "SEND", callMethod = "send"),
        @Transit(from = "WAIT_RECEIVE", to = "COMPLETE", on = "COMPLETE", callMethod = "complete")
})
// @StateMachineParameters用来声明状态机泛型参数类型,向AbstractStateMachine传递参数
@StateMachineParameters(stateType = OrderState.class, eventType = OrderEvent.class, contextType = OrderContext.class)
@Slf4j
public class SubmitOrderStateMachine extends AbstractStateMachine<UntypedStateMachine, Object, Object, Object> implements UntypedStateMachine {

    private OrderService orderService;
    protected ApplicationContext applicationContext;
    
    //定义构造函数接受ApplicationContext注入
    //([参看New State Machine Instance](http://hekailiang.github.io/squirrel/))
    public SubmitOrderStateMachine(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        // 通过applicationContext注入orderService
        this.orderService = applicationContext.getBean(OrderService.class);
    }

    // 状态转换时调用的方法,需要将方法名配置在 callMethod 内
    // 若【方法名】符合 transitFrom[fromStateName]To[toStateName] 格式,不需要配置 callMethod
    public void submitOrder(OrderState fromState, OrderState toState, OrderEvent Event, OrderContext Context) {
        log.info("转换事件 {}=>{} on {} with {}.", fromState, toState, event, context);
        orderService.submitOrder(toState);
    }
    
    ...

    public void complete(OrderState fromState, OrderState toState, OrderEvent Event, OrderContext Context) {
        log.info("转换事件 {}=>{} on {} with {}.", fromState, toState, event, context);
        System.out.println("complete");
    }

    // 符合 entry[StateName] 格式,不需要配置 callMethod
    public void entryStateInit(OrderState fromState, OrderState toState, OrderEvent Event, OrderContext Context) {
        log.info("进入状态 {}=>{} on {} with {}.", from, to, event, context);
        System.out.println("entryStateInit");
    }

    // 符合 exit[StateName] 格式,不需要配置 callMethod
    public void exitStateInit(OrderState fromState, OrderState toState, OrderEvent Event, OrderContext Context) {
        log.info("退出状态 {}=>{} on {} with {}.", from, to, event, context);
        System.out.println("exitStateInit");
    }
    
    ...
    
    // ==========================================================================================
    // 如果不想用 DeclarativeEventListener 这种声明在单独类里的方法,可以直接重写以下方法,效果是一样的
    // 两者同时用也可以,为了代码方便最好别这样
    // ==========================================================================================
    @Override
    protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {
        /**
        * 当状态转换过程中出现异常,已执行的action列表将失效并且状态机会进入error状态,意思就是状态机实例不会再处理任何event。假如用户继续向状态机发送event,便会抛出IllegalStateException异常。所有状态转换过程中发生的异常,包括action执行和外部listener调用,会被包装成TransitionException(未检查异常)。目前,默认的异常处理策略非常简单并且粗暴的连续抛出异常,可以参阅AbstractStateMachine.afterTransitionCausedException方法。
        */
        log.info("Override 发生错误 {}", getLastException().getMessage());
        Throwable targeException = getLastException().getTargetException();
    // recover from IllegalArgumentException thrown out from state 'A' to 'B' caused by event 'ToB'
        if(targeException instanceof IllegalArgumentException &&
                fromState.equals("A") && toState.equals("B") && event.equals("ToB")) {
            // do some error clean up job here
            // ...
            // after recovered from this exception, reset the state machine status back to normal
            setStatus(StateMachineStatus.IDLE);
        } else if(...) {
            // recover from other exception ...
        } else {
             // afterTransitionCausedException 默认的实现是直接抛异常
            super.afterTransitionCausedException(fromState, toState, event, context);
        }
    }
    @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");
        if (context instanceof StateMachineContext && toState instanceof State) {
            StateMachineContext stateMachineContext = (StateMachineContext)context;
            //从上下文中获取需要持久化的数据,例如订单ID等
            Rma rma = stateMachineContext.get(MessageKeyEnum.RMA);
            //持久化
            rma.setStatus((State)toState);
            this.applicationContext.get("rmaRepository").updateRma(rma);
        } else {
            throw new Exception("type not support, context expect " + StateMachineContext.class.getSimpleName() + ", actually "
                    + context.getClass().getSimpleName() + ", state expect " + State.class.getSimpleName()
                    + ", actually "
                    + toState.getClass().getSimpleName());
        }
    }
    @Override
    protected void afterTransitionEnd(Object fromState, Object toState, Object event, Object context) {
        // 转换结束时被调用
 //       super.afterTransitionEnd(fromState, toState, event, context);
        log.info("Override afterTransitionEnd");
    }
    @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");
    }
}


定义状态枚举、事件枚举、上下文

定义状态枚举

@Get
public enum OrderState {
    INIT(1,"开始"),
    WAIT_PAY(2,"待支付"),
    WAIT_SEND(3,"待发送"),
    PART_SEND(4,"配送"),
    WAIT_RECEIVE(5,"待接收"),
    COMPLETE(6,"完成"),
    CANCELED(7,"取消");
    
    private String desc;
    private int code;

    public static OrderState getState(String state) {
        for (OrderState orderState : OrderState.values()) {
            if (orderState.name().equalsIgnoreCase(state)) {
                return orderState;
            }
        }
        return null;
    }
    
    public static OrderStates getState(int code) {
        for (OrderStates orderState : OrderStates.values()) {
            if (orderState.ordinal()+1 == code) {
                return orderState;
            }
        }
        return null;
    }
}

定义事件枚举

public enum OrderEvent {

    SUBMIT_ORDER,    //提交订单;INIT ==> WAIT_PAY
    PAY,            //支付完成;WAIT_PAY ==> WAIT_SEND
    PART_SEND,        //等待配送;WAIT_SEND ==> PART_SEND
    SEND,            //配送中;PART_SEND ==> WAIT_RECEIVE
    COMPLETE        //完成;WAIT_RECEIVE ==> COMPLETE
}

定义上下文

@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderContext {
    public OrderDTO orderDTO;
}


业务相关代码

Service的实现,更新订单状态

@Service
public class OrderService {

    @Autowired
    OrderDTOMapper orderDTOMapper;

    public int submitOrder(OrderState state) {
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setState(state);
        orderDTOMapper.insert(orderDTO);
        return 1;
    }
}

mapper

@Mapper
public interface OrderDTOMapper {

    int insert(OrderDTO orderDTO);

}

订单的实体

@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderDTO {

    private Integer id;

    private OrderState state;

    private Date createTime;

    private Date updateTime;
}


定义监听器

可以不用 DeclarativeEventListener 这种声明在单独类里的形式

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

/**
 * 声明式监听
 */
@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");
    }
}


Controller 类测试

注入OrderStateMachineEngine ,初始化状态为INIT,通过OrderStateMachineEngine 触发SUBMIT_ORDER事件,发生状态变化,并将转换后的状态插入数据库

@RestController
@RequestMapping(value = "/order/")
public class OrderController {

    // 注入状态机
    @Autowired
    OrderStateMachineEngine orderStateMachineEngine;


    @RequestMapping("/test")
    public void test(){
        OrderDTO orderDTO = new OrderDTO(OrderState.INIT);
        OrderContext orderContext = new OrderContext(orderDTO);
        // 启动状态机,触发某事件,发生状态变化
        orderStateMachineEngine.fire(OrderEvent.SUBMIT_ORDER,orderContext);
    }
}


流式 API 式状态机

参考:Squirrel使用

状态机引擎

StateMachine 接口需要以下 4 种泛型参数。

  • T 代表实现的状态机类型。
  • S 代表实现的状态类型。
  • E 代表实现的事件类型。
  • C 代表实现的外部上下文类型。
/**
 * 创建状态机
 * 通过Spring创建StateMachineBuilder实例,通过buidler创建状态机(单例)
 * 业务函数中通过StateMachineBuilder实例创建StateMachine实例,并向StateMachine暴露SpringApplicationContext,以便于StateMachine通过ApplicationContext获取数据层的对象
*/
@Slf4j
@Componet
public class StateMachineEngine implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    protected StateMachineBuilder<MyStateMachine, MyState, MyEvent, MyContext> builder;

    @SuppressWarnings("unchecked")
    public StateMachineEngine() {
        builder = StateMachineBuilderFactory.create(
            MyStateMachine.class, MyState.class, MyEvent.class, MyContext.class);
        // 状态机builder创建之后,可以使用流失API来定义状态机的state/transition/action
        // 创建一个状态从状态A到B,并且MyEvent.GoToB事件触发,调用MyCallMethod动作方法的externalTransition
        builder.externalTransition().from(MyState.A).to(MyState.B).on(MyEvent.GoToB)
            .callMethod = "MyCallMethod";
    }
    //注入applicationContext,并在创建StateMachine实例时注入
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
    *    可以通过向OrderContext 上下文传递一些业务参数,比如orderId等等
    */
    public boolean fire(EOrderEvents event, OrderContext context) {
        MyStateMachine stateMachine = stateMachineBuilder.newStateMachine(
                context.geteOrder().getOrderStatus(),applicationContext);
        
        //由于StateMachine实例不是由Spring容器创建,所以这个过程中无法通过注解方式开启事务(Spring没有机会去创建事务代理),因此采用了编程式事务
        DataSourceTransactionManager transactionManager = (DataSourceTransactionManager)applicationContext.getBean("transactionManager");
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            stateMachine.fire(event, context);
            transactionManager.commit(status);
            //这里会返回状态机是否出错,如果出错可用于通知Controller层
            return stateMachine.isError();
        } catch (Exception ex) {
            //用于事务回滚
            transactionManager.rollback(status);
            return true;
        }
    }
}


定义状态机

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

/**
 * 定义 触发事件、状态变化时,调用的方法
*/
@Slf4j
public class MyStateMachine extends AbstractStateMachine<MyStateMachine, MyState, MyEvent, MyContext> {

    private MyService myService;
    protected ApplicationContext applicationContext;
    
    //定义构造函数接受ApplicationContext注入
    public SubmitOrderStateMachine(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        // 通过applicationContext注入orderService
        this.myService = applicationContext.getBean(MyService.class);
    }

    // 状态转换时调用的方法,需要将方法名配置在 callMethod 内
    // 若【方法名】符合 transitFrom[fromStateName]To[toStateName] 格式,不需要配置 callMethod
    public void MyCallMethod(MyState fromState, OrderState MyState,MyEvent Event, MyContext Context) {
        log.info("转换事件 {}=>{} on {} with {}.", fromState, toState, event, context);
        myService.myMethod(toState);
    }
    
    ...
    
    // ==========================================================================================
    // 如果不想用 DeclarativeEventListener 这种声明在单独类里的方法,可以直接重写以下方法,效果是一样的
    // 两者同时用也可以,为了代码方便最好别这样
    // ==========================================================================================
    @Override
    protected void afterTransitionCausedException(Object fromState, Object toState, Object event, Object context) {
        /**
        * 当状态转换过程中出现异常,已执行的action列表将失效并且状态机会进入error状态,意思就是状态机实例不会再处理任何event。假如用户继续向状态机发送event,便会抛出IllegalStateException异常。所有状态转换过程中发生的异常,包括action执行和外部listener调用,会被包装成TransitionException(未检查异常)。目前,默认的异常处理策略非常简单并且粗暴的连续抛出异常,可以参阅AbstractStateMachine.afterTransitionCausedException方法。
        */
        log.info("Override 发生错误 {}", getLastException().getMessage());
        Throwable targeException = getLastException().getTargetException();
        // recover from IllegalArgumentException thrown out from state 'A' to 'B' caused by event 'ToB'
        if(targeException instanceof IllegalArgumentException &&
                fromState.equals("A") && toState.equals("B") && event.equals("ToB")) {
            // 在这里做一些错误清理工作
            // ...
            // 恢复此异常后,将状态机状态恢复为正常状态
            setStatus(StateMachineStatus.IDLE);
        } else if(...) {
            // 从其他异常中恢复...
        } else {
             // afterTransitionCausedException 默认的实现是直接抛异常
            super.afterTransitionCausedException(fromState, toState, event, context);
        }
    }
    @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");
    }
    @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");
    }
}


定义状态枚举、事件枚举、上下文

略(同声明式状态机)

相关文章
|
3月前
qt 手搓ui
qt 手搓ui
43 3
|
6月前
|
数据可视化
ggGenshin&Genshinpalette|SCI绘图遇上原神,不输于CNS正刊调色板
本文介绍了两个R包——`ggGenshin`和`Genshinpalette`,它们提供了基于热门游戏《原神》角色色彩的调色板,用于数据可视化。`ggGenshin`包包含了一系列与游戏角色相关的颜色,可以方便地应用到`ggplot2`图形中,而`Genshinpalette`包则提供了更多角色的配色选项。通过这两个包,用户可以直接使用预设的配色方案,提升图表的视觉效果。文中还展示了使用这些调色板绘制的一些示例图表。
266 0
|
Python
Python 代码绘制航海王四皇大妈(BIG MOM) - 门卫大爷也能跟着学会的Turtle海龟绘图系列
Python 代码绘制航海王四皇大妈(BIG MOM) - 门卫大爷也能跟着学会的Turtle海龟绘图系列
154 0
福利来了:vaw-layouts,来不及解释了,赶紧上车
继vue-admin-work开源框架开发完之后,请多小伙伴问我,要怎么样快速搭建公司的后台管理系统。目前的解决方案是在 vue-admin-work的基础上进行删除无用的代码或者修改自己的需求。当了解了这一需求之后,我们想了一下也确实不方便,所以为了解决这一痛点 vaw-layouts项目就正式诞生了。
福利来了:vaw-layouts,来不及解释了,赶紧上车
|
图形学 开发者
Unity【Dynamic Bone】- 关于人物模型头发、衣物等细节的处理
Unity【Dynamic Bone】- 关于人物模型头发、衣物等细节的处理
391 0
Unity【Dynamic Bone】- 关于人物模型头发、衣物等细节的处理
大声说出你对女神的爱!Geek is A choice. Girls make difference.
女王节来了,我们采访了来自于阿里云智能一线的6位geek girl,用两天的时间近距离观察她们快乐工作的,还在银泰百货的支持下绽放她们认真生(chou)活(mei)的光芒。 雏恬 我不想做被保护的女生,我想做改变世界的极客。
Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)
原文:Silverlight & Blend动画设计系列十三:三角函数(Trigonometry)动画之飘落的雪花(Falling Snow)   平时我们所看到的雪花(Falling Snow)飘飘的效果实际上也是一个动画,是由许多的动画对象共同完成的一个界面效果。
962 0
零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里
原文:零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里 本章将教大家如何在Blend 4里新增Media Element,以及运用Video Brush让影片镶入你所设定的字里,使影片不再是传统的呈现方式。
1287 0