有限状态机简称就是状态机,因为一般的状态机的状态都是离散和可举的,即为有限,所以后面的介绍都不加有限二字。状态机表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。通俗的描述状态机就是定义了一套状态変更的流程:状态机包含一个状态集合,定义当状态机处于某一个状态的时候它所能接收的事件以及可执行的行为,执行完成后,状态机所处的状态。所以状态机会包含以下几个重要的元素:
如果你写过很复杂的流程系统,流程系统中涉及多步操作,流程达到不同的状态需要有不同的处理,同时状态间的转换也是有特定逻辑的。如果不使用状态机,那么你的代码我估计会有大量的if判断语句,你得判断某个操作指令过来了,当前这个状态是否能执行该指令。
Spring中有集成了一套状态机框架,我们可以使用该框架进行开发。假设我们使用的Springboot为2.1.9
pom
<dependency>
   <groupId>org.springframework.statemachine</groupId>
   <artifactId>spring-statemachine-starter</artifactId>
   <version>2.2.0.RELEASE</version>
</dependency>
<dependency>
   <groupId>org.springframework.statemachine</groupId>
   <artifactId>spring-statemachine-core</artifactId>
   <version>2.2.0.RELEASE</version>
</dependency>我们定义两个枚举,一个为订单状态,一个为订单事件。
public enum OrderStatus {
    CREATED,
    WAITINF_FOR_RECEIVE,
    FINISHED
}public enum OrderEvents {
    PAY,
    RECEIVE
}设置一个状态机配置bean
@Configuration
@EnableStateMachine
@Slf4j
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStatus,OrderEvents> {
    /**
     * 状态机侦听器的bean
     * @return
     */
    @Bean
    public StateMachineListener<OrderStatus,OrderEvents> listener() {
        return new StateMachineListenerAdapter<OrderStatus,OrderEvents>() {
            @Override
            public void stateChanged(State<OrderStatus, OrderEvents> from, State<OrderStatus, OrderEvents> to) {
                log.info("State change to {}",to.getId());
            }
        };
    }
    /**
     * 状态机执行器的bean
     * @return
     */
    @Bean
    public Action<OrderStatus,OrderEvents> action() {
        return new Action<OrderStatus, OrderEvents>() {
            @Override
            public void execute(StateContext<OrderStatus, OrderEvents> stateContext) {
                log.info("from {} to {}",stateContext.getSource().getId(),stateContext.getTarget().getId());
            }
        };
    }
    /**
     * 注册侦听器
     * @param config
     * @throws Exception
     */
    @Override
    public void configure(StateMachineConfigurationConfigurer<OrderStatus, OrderEvents> config) throws Exception {
        config.withConfiguration()
                .autoStartup(true)
                .listener(listener());
    }
    /**
     * 初始化订单状态
     * @param states
     * @throws Exception
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatus, OrderEvents> states) throws Exception {
        states.withStates()
                .initial(OrderStatus.CREATED)
                .states(EnumSet.allOf(OrderStatus.class));
    }
    /**
     * 订单状态转变时对应的事件和执行器
     * @param transitions
     * @throws Exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvents> transitions) throws Exception {
        transitions.withExternal().source(OrderStatus.CREATED).target(OrderStatus.WAITINF_FOR_RECEIVE)
                .event(OrderEvents.PAY).action(action())
                .and()
                .withExternal().source(OrderStatus.WAITINF_FOR_RECEIVE).target(OrderStatus.FINISHED)
                .event(OrderEvents.RECEIVE).action(action());
    }
}Springboot引导类
@SpringBootApplication
public class CalculateApplication implements CommandLineRunner{
   @Autowired
   private StateMachine<OrderStatus,OrderEvents> stateMachine;
   public static void main(String[] args) {
      SpringApplication.run(CalculateApplication.class, args);
   }
   @Override
   public void run(String... args) throws Exception {
      stateMachine.sendEvent(OrderEvents.PAY);
      stateMachine.sendEvent(OrderEvents.RECEIVE);
   }
}运行可见如下日志
2020-06-02 03:41:20.007  INFO 22287 --- [           main] c.g.calculate.state.StateMachineConfig   : from CREATED to WAITINF_FOR_RECEIVE
2020-06-02 03:41:20.008  INFO 22287 --- [           main] c.g.calculate.state.StateMachineConfig   : State change to WAITINF_FOR_RECEIVE
2020-06-02 03:41:20.008  INFO 22287 --- [           main] c.g.calculate.state.StateMachineConfig   : from WAITINF_FOR_RECEIVE to FINISHED
2020-06-02 03:41:20.009  INFO 22287 --- [           main] c.g.calculate.state.StateMachineConfig   : State change to FINISHED