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


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

略(同声明式状态机)

相关文章
Doodle Jump — 使用Flutter&Flame开发游戏真不错!
用Flutter&Flame开发游戏是一种什么体验?最近网上冲浪的时候,我偶然发现了一个国外的游戏网站,类似于国内的4399。在浏览时,我遇到了一款经典的小游戏:Doodle Jump...
112797 12
|
4天前
|
人工智能
大模型battle,哪家才是真的“价美”也“物美”
【6月更文挑战第10天】大模型battle,哪家才是真的“价美”也“物美”
|
30天前
|
JavaScript 开发者
【掰开揉碎】深入了解 @tap 和 @click
【掰开揉碎】深入了解 @tap 和 @click
|
30天前
|
XML Android开发 数据格式
Dialog里面用ComposeView竟会直接闪退?深挖Lifecycle与Compose的爱恨情仇
Dialog里面用ComposeView竟会直接闪退?深挖Lifecycle与Compose的爱恨情仇
140 0
|
8月前
|
Python
【端午趣味征文】有vcs和python吗?来,我教你在波形里画个粽子!
【端午趣味征文】有vcs和python吗?来,我教你在波形里画个粽子!
|
数据可视化 数据挖掘 定位技术
森林野火故事2.0:一眼看穿!使用 Panel 和 hvPlot 可视化 ⛵
本文讲解使用Panel、hvPlot等工具库,简单快速地制作可交互的数据仪表板,对180万起野火数据进行空间可视化,更直观地对起火原因、火势大小、持续时长进行单维或多维分析。
801 2
森林野火故事2.0:一眼看穿!使用 Panel 和 hvPlot 可视化 ⛵
|
Android开发
android源码宇宙-StateFlow
android源码宇宙-StateFlow
423 0
android源码宇宙-StateFlow
智能情侣枕Pillow Talk,倾听彼此的心跳
能稍微缓解相思之苦的智能情侣枕头Pillow Talk。
618 0
|
前端开发 C# Windows
利刃 MVVMLight 7:命令深入
原文:利刃 MVVMLight 7:命令深入   上面一篇我们大致了解了命令的基本使用方法和基础原理,但是实际在运用命令的时候会复杂的多,并且会遇到各种各样的情况。 一、命令带参数的情况: 如果视图控件所绑定的命令想要传输参数,需要配置 CommandParameter 属性 ,用来传输参数出去。
862 0

热门文章

最新文章