目录

有限状态机

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

状态机的四大概念。

  • State ,状态。一个状态机至少要包含两个状态。
  • Event ,事件。事件就是执行某个操作的触发条件或者口令。
  • Action ,动作。事件发生以后要执行动作。
  • Transition ,变换。也就是从一个状态变化为另一个状态。

状态转移表

当前状态→条件↓ 状态A 状态B 状态C
条件X
条件Y 状态C
条件Z

状态机实现方式

MQ驱动:

订单状态的流转可以通过MQ发布一个事件,消费者根据业务条件把订单状态进行流转,可以根据不同的事件发送到不同的Topic,使得业务逻辑更清晰

Job驱动:

每隔一段时间启动一下job,根据特定的状态从数据库中拿对应的订单记录,然后判断订单是否有条件到达下一个状态

轻量级状态机:

Spring 里也有这样的组件,Spring Statemachine

上面三种方式非常轻量级,落地容易,如果不涉及非常多的状态流转或复杂的判断条件,就推荐使用这些方式

规则引擎:

这种方式比较重量级,通常是大厂才使用的玩法。业务团队可以在规则引擎里自行配置规则,不需要技术团队做发布和代码变更

Spring Statemachine

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public enum OrderState {
  /*
    创建订单
     */
    CREATED,
    /*
    等待付款
     */
    PENDING_PAYMENT,
    /*
    等待配送
     */
    PENDING_DELIVERY,
    /*
    订单完结
     */
    ORDER_COMPLETE
}

public enum OrderEvent {
  /*下单*/
  PLACE_ORDER,
  /*付款完成*/
  PAID,
  /*配送成功*/
  DELIVERED
}

@WithStateMachine
@Slf4j
public class OrderListener{
  private String orderStatus =OrderState.CREATED.name();
    /**
    * 注解中传入的是目标状态
    *
    * @param message 可以从message中拿出一些属性
    */
    @OnTransition(target ="PENDING_PAYMENT")
    public void pendingPayment(Message message){
      // TODO 模拟业务流程setOrderStatus(OrderState.PENDING_PAYMENT.name());
      log.info("订单创建,等待付款, status={} header={}",OrderState.PENDING_PAYMENT.name(),
                message.getHeaders().get("orderId"));
    }
    @OnTransition(target ="PENDING_DELIVERY")
    public void pendingDelivery(){
      // TODO 模拟业务流程setOrderStatus(OrderState.PENDING_DELIVERY.name());
      log.info("订单已付款,等待发货, status={} ",OrderState.PENDING_DELIVERY.name());
    }
    @OnTransition(target ="ORDER_COMPLETE")
    public void complete(){
      // TODO 模拟业务流程setOrderStatus(OrderState.ORDER_COMPLETE.name());
      log.info("订单完成, status={}",OrderState.ORDER_COMPLETE.name());
    }
  }
  • 使用@WithStateMachine注解开启状态机功能
  • 被@OnTransition(target = “PENDING_PAYMENT”)注解的方法表示该操作会使状态流转至PENDING_PAYMENT
  • 定义pendingPayment方法表示用户创建订单操作
  • 定义pendingDelivery方法表示用户付款操作
  • 定义complete方法表示用户签收操作,订单状态变为完结
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState,OrderEvent> {
  @Override
  public void configure(StateMachineStateConfigurer<OrderState,OrderEvent> states) throws Exception {
    // 指定初始化状态
    states.withStates().initial(OrderState.CREATED).states(EnumSet.allOf(OrderState.class));
  }
  /**
  * 配置状态机如何做流转
  * @param transitions
  * @throws Exception
  */@Override
  public void configure(StateMachineTransitionConfigurer<OrderState,OrderEvent> transitions) throws Exception {
    transitions
      .withExternal()
      .source(OrderState.CREATED)
      .target(OrderState.PENDING_PAYMENT)
      .event(OrderEvent.PLACE_ORDER)
      .and().withExternal()
      .source(OrderState.PENDING_PAYMENT).target(OrderState.PENDING_DELIVERY).event(OrderEvent.PAID)
      .and().withExternal()
      .source(OrderState.PENDING_DELIVERY).target(OrderState.ORDER_COMPLETE).event(OrderEvent.DELIVERED);
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class MyRunner implements CommandLineRunner {

  @Resource StateMachine<OrderState,OrderEvent> stateMachine;

  @Override
  public void run(String... args) throws Exception {
    stateMachine.start();
    Message message = MessageBuilder.withPayload(OrderEvent.PLACE_ORDER).setHeader("orderId","998").build();
    stateMachine.sendEvent(message);
    stateMachine.sendEvent(OrderEvent.PAID);
    stateMachine.sendEvent(OrderEvent.DELIVERED);
  }
}

Message 是 spring-messaging 模块中的

此外,Spring Statemachine 还有一些高级功能:

  • Guard:状态准入、判断当前业务是否可以进入下个状态
  • Action:状态转移之后执行的业务逻辑

附录