【设计模式】状态机详解与Spring State Machine实践

状态机详解与Spring State Machine实践

目录

  1. 状态机基础
    • 1.1 什么是状态机
    • 1.2 状态机的基本概念
    • 1.3 状态机类型
  2. Spring State Machine概述
    • 2.1 核心组件
    • 2.2 工作原理
  3. Spring State Machine实战 - 订单状态流转
    • 3.1 环境配置
    • 3.2 状态与事件定义
    • 3.3 状态机配置
    • 3.4 状态机持久化
    • 3.5 状态监听器实现
    • 3.6 状态事件工具类
    • 3.7 业务服务实现
    • 3.8 接口控制器
    • 3.9 运行效果展示
  4. 注意事项与最佳实践
  5. 其他状态机实现方案
    • 5.1 消息队列方式
    • 5.2 定时任务驱动
    • 5.3 规则引擎方式
  6. 项目结构
  7. 总结

状态机基础

什么是状态机

状态机(State Machine)是一种数学模型,用于描述系统在不同状态之间转换的行为。它通过定义一系列有限的状态以及状态之间的转换规则,来模拟现实世界或抽象系统的动态行为。每个状态代表系统可能存在的条件或阶段,而状态间的转换则是由特定的输入(即事件)触发的。

状态机的基本概念

  1. 状态(State):系统处于的特定状态,可以是任何抽象的状态,如"开"、“关”,或是更具体的状态如"运行"、"暂停"等。
  2. 事件(Event):导致状态转换发生的触发器或输入,例如用户的操作、外部事件等。
  3. 转移(Transition):描述状态之间的变化或转换,即从一个状态到另一个状态的过程。
  4. 动作(Action):在状态转换发生时执行的操作,可以是逻辑处理、计算、输出等。
  5. 初始状态(Initial State):系统的初始状态,即系统启动时所处的状态。
  6. 终止状态(Final State):状态机执行完成后所达到的状态,表示整个状态机的结束。

状态机类型

状态机可以分为有限状态机(Finite State Machine,FSM)和无限状态机(Infinite State Machine)两种。有限状态机是指状态的数量是有限的,而无限状态机则可以有无限多个状态。在系统设计中,有限状态机更为常见。

Spring State Machine概述

Spring State Machine是Spring生态系统中的一个框架,它提供了实现状态机模式的完整解决方案。它建立在有限状态机(FSM)的概念之上,提供了一种简洁且灵活的方式来定义、管理和执行状态机。

核心组件

Spring State Machine的核心主要包括以下三个关键元素:

  1. 状态(State):定义了系统可能处于的各个状态,如订单状态中的待支付、已支付等。
  2. 转换(Transition):描述了在何种条件下,当接收到特定事件时,系统可以从一个状态转移到另一个状态。
  3. 事件(Event):触发状态转换的动作或者消息,它是引起状态机从当前状态迁移到新状态的原因。

工作原理

Spring State Machine将状态定义为Java对象,并通过配置来定义状态之间的转换规则。状态转换通常由外部事件触发,可以根据业务逻辑定义不同的事件类型,并与状态转换关联。它还提供了状态监听器,用于在状态变化时执行特定的逻辑。同时,状态机的状态可以持久化到数据库或其他存储介质中,以便在系统重启或故障恢复时保持状态的一致性。

Spring State Machine实战 - 订单状态流转

接下来,我们将通过一个具体的例子来说明如何使用Spring State Machine来实现订单状态的流转。

环境配置

首先,需要引入Spring State Machine的依赖:

<dependency>
    <groupId>org.springframework.statemachinegroupId>
    <artifactId>spring-statemachine-starterartifactId>
    <version>2.2.1.RELEASEversion>
dependency>

状态与事件定义

定义订单状态和触发状态转换的事件:

/**
 * 订单状态
 */
public enum OrderStatusEnum {
    /**待提交*/
    DRAFT,
    /**待出库*/
    SUBMITTED,
    /**已出库*/
    DELIVERING,
    /**已签收*/
    SIGNED,
    /**已完成*/
    FINISHED,
    ;
}

/**
 * 订单状态流转事件
 */
public enum OrderStatusOperateEventEnum {
    /**确认,已提交*/
    CONFIRMED,
    /**发货*/
    DELIVERY,
    /**签收*/
    RECEIVED,
    /**完成*/
    CONFIRMED_FINISH,
    ;
}

状态机配置

配置状态机的状态和转换规则:

@Configuration
@EnableStateMachine(name = "orderStateMachine")
public class OrderStatusMachineConfig extends StateMachineConfigurerAdapter<OrderStatusEnum, OrderStatusOperateEventEnum> {

    /**
     * 设置状态机的状态
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderStatusEnum, OrderStatusOperateEventEnum> states) throws Exception {
        states.withStates()
                .initial(OrderStatusEnum.DRAFT)
                .end(OrderStatusEnum.FINISHED)
                .states(EnumSet.allOf(OrderStatusEnum.class));
    }

    /**
     * 设置状态机与订单状态操作事件绑定
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderStatusEnum, OrderStatusOperateEventEnum> transitions) throws Exception {
        transitions.withExternal().source(OrderStatusEnum.DRAFT).target(OrderStatusEnum.SUBMITTED)
                .event(OrderStatusOperateEventEnum.CONFIRMED)
                .and()
                .withExternal().source(OrderStatusEnum.SUBMITTED).target(OrderStatusEnum.DELIVERING)
                .event(OrderStatusOperateEventEnum.DELIVERY)
                .and()
                .withExternal().source(OrderStatusEnum.DELIVERING).target(OrderStatusEnum.SIGNED)
                .event(OrderStatusOperateEventEnum.RECEIVED)
                .and()
                .withExternal().source(OrderStatusEnum.SIGNED).target(OrderStatusEnum.FINISHED)
                .event(OrderStatusOperateEventEnum.CONFIRMED_FINISH);
    }
}

状态机持久化

配置状态机的持久化,保证状态信息不会丢失:

@Configuration
public class OrderPersist {

    /**
     * 持久化配置
     * 在实际使用中,可以配合数据库或者Redis等进行持久化操作
     */
    @Bean
    public DefaultStateMachinePersister<OrderStatusEnum, OrderStatusOperateEventEnum, OrderDO> stateMachinePersister(){
        Map<OrderDO, StateMachineContext<OrderStatusEnum, OrderStatusOperateEventEnum>> map = new HashMap();
        return new DefaultStateMachinePersister<>(new StateMachinePersist<OrderStatusEnum, OrderStatusOperateEventEnum, OrderDO>() {
            @Override
            public void write(StateMachineContext<OrderStatusEnum, OrderStatusOperateEventEnum> context, OrderDO order) throws Exception {
                //持久化操作
                map.put(order, context);
            }

            @Override
            public StateMachineContext<OrderStatusEnum, OrderStatusOperateEventEnum> read(OrderDO order) throws Exception {
                //从库中或者redis中读取order的状态信息
                return map.get(order);
            }
        });
    }
}

状态监听器实现

实现状态监听器,监听状态变化并执行相应的业务逻辑:

@Component
@WithStateMachine(name = "orderStateMachine")
public class OrderStatusListener {

    @OnTransition(source = "DRAFT", target = "SUBMITTED")
    public boolean payTransition(Message<OrderStatusOperateEventEnum> message) {
        OrderDO order = (OrderDO) message.getHeaders().get("order");
        order.setOrderStatusEnum(OrderStatusEnum.SUBMITTED);
        System.out.println(String.format("出库订单[%s]确认,状态机信息:%s", order.getOrderNo(), message.getHeaders()));
        return true;
    }

    @OnTransition(source = "SUBMITTED", target = "DELIVERING")
    public boolean deliverTransition(Message<OrderStatusOperateEventEnum> message) {
        OrderDO order = (OrderDO) message.getHeaders().get("order");
        order.setOrderStatusEnum(OrderStatusEnum.DELIVERING);
        System.out.println(String.format("出库订单[%s]发货出库,状态机信息:%s", order.getOrderNo(), message.getHeaders()));
        return true;
    }

    @OnTransition(source = "DELIVERING", target = "SIGNED")
    public boolean receiveTransition(Message<OrderStatusOperateEventEnum> message){
        OrderDO order = (OrderDO) message.getHeaders().get("order");
        order.setOrderStatusEnum(OrderStatusEnum.SIGNED);
        System.out.println(String.format("出库订单[%s]签收,状态机信息:%s", order.getOrderNo(), message.getHeaders()));
        return true;
    }

    @OnTransition(source = "SIGNED", target = "FINISHED")
    public boolean finishTransition(Message<OrderStatusOperateEventEnum> message){
        OrderDO order = (OrderDO) message.getHeaders().get("order");
        order.setOrderStatusEnum(OrderStatusEnum.FINISHED);
        System.out.println(String.format("出库订单[%s]完成,状态机信息:%s", order.getOrderNo(), message.getHeaders()));
        return true;
    }
}

状态事件工具类

创建状态事件的工具类,用于发送状态转换事件:

@Component
public class StateEventUtil {

    private StateMachine<OrderStatusEnum, OrderStatusOperateEventEnum> orderStateMachine;

    private StateMachinePersister<OrderStatusEnum, OrderStatusOperateEventEnum, OrderDO> stateMachinePersister;

    /**
     * 发送状态转换事件
     * synchronized修饰保证这个方法是线程安全的
     */
    public synchronized boolean sendEvent(Message<OrderStatusOperateEventEnum> message) {
        boolean result = false;
        try {
            //启动状态机
            orderStateMachine.start();
            OrderDO order = (OrderDO) message.getHeaders().get("order");
            //尝试恢复状态机状态
            stateMachinePersister.restore(orderStateMachine, order);
            result = orderStateMachine.sendEvent(message);
            //持久化状态机状态
            stateMachinePersister.persist(orderStateMachine, order);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (Objects.nonNull(message)) {
                OrderDO order = (OrderDO) message.getHeaders().get("order");
                if (Objects.nonNull(order) && Objects.equals(order.getOrderStatusEnum(), OrderStatusEnum.FINISHED)) {
                    orderStateMachine.stop();
                }
            }
        }
        return result;
    }

    @Autowired
    public void setOrderStateMachine(StateMachine<OrderStatusEnum, OrderStatusOperateEventEnum> orderStateMachine) {
        this.orderStateMachine = orderStateMachine;
    }

    @Autowired
    public void setStateMachinePersister(StateMachinePersister<OrderStatusEnum, OrderStatusOperateEventEnum, OrderDO> stateMachinePersister) {
        this.stateMachinePersister = stateMachinePersister;
    }
}

业务服务实现

实现订单服务,处理订单状态流转的业务逻辑:

@Service
public class OrderServiceImpl implements IOrderService {

    private StateEventUtil stateEventUtil;

    private static final AtomicInteger ID_COUNTER = new AtomicInteger(0);

    private static final Map<Long, OrderDO> ORDER_MAP = new ConcurrentHashMap<>();

    /**
     * 创建新订单
     */
    @Override
    public Long createOrder(OrderDO orderDO) {
        long orderId = ID_COUNTER.incrementAndGet();
        orderDO.setOrderId(orderId);
        orderDO.setOrderNo("OC20240306" + orderId);
        orderDO.setOrderStatusEnum(OrderStatusEnum.DRAFT);
        ORDER_MAP.put(orderId, orderDO);
        System.out.println(String.format("订单[%s]创建成功:", orderDO.getOrderNo()));
        return orderId;
    }

    /**
     * 确认订单
     */
    @Override
    public void confirmOrder(Long orderId) {
        OrderDO order = ORDER_MAP.get(orderId);
        System.out.println("确认订单,订单号:" + order.getOrderNo());
        Message message = MessageBuilder.withPayload(OrderStatusOperateEventEnum.CONFIRMED).
                setHeader("order", order).build();
        if (!stateEventUtil.sendEvent(message)) {
            System.out.println(" 确认订单失败, 状态异常,订单号:" + order.getOrderNo());
        }
    }

    /**
     * 订单发货
     */
    @Override
    public void deliver(Long orderId) {
        OrderDO order = ORDER_MAP.get(orderId);
        System.out.println("订单出库,订单号:" + order.getOrderNo());
        Message message = MessageBuilder.withPayload(OrderStatusOperateEventEnum.DELIVERY).
                setHeader("order", order).build();
        if (!stateEventUtil.sendEvent(message)) {
            System.out.println(" 订单出库失败, 状态异常,订单号:" + order.getOrderNo());
        }
    }

    /**
     * 签收订单
     */
    @Override
    public void signOrder(Long orderId) {
        OrderDO order = ORDER_MAP.get(orderId);
        System.out.println("订单签收,订单号:" + order.getOrderNo());
        Message message = MessageBuilder.withPayload(OrderStatusOperateEventEnum.RECEIVED).
                setHeader("order", order).build();
        if (!stateEventUtil.sendEvent(message)) {
            System.out.println(" 订单签收失败, 状态异常,订单号:" + order.getOrderNo());
        }
    }

    /**
     * 确认完成
     */
    @Override
    public void finishOrder(Long orderId) {
        OrderDO order = ORDER_MAP.get(orderId);
        System.out.println("订单完成,订单号:" + order.getOrderNo());
        Message message = MessageBuilder.withPayload(OrderStatusOperateEventEnum.CONFIRMED_FINISH).
                setHeader("order", order).build();
        if (!stateEventUtil.sendEvent(message)) {
            System.out.println(" 订单完成失败, 状态异常,订单号:" + order.getOrderNo());
        }
    }

    /**
     * 获取所有订单信息
     */
    @Override
    public List<OrderDO> listOrders() {
        return new ArrayList<>(ORDER_MAP.values());
    }

    @Autowired
    public void setStateEventUtil(StateEventUtil stateEventUtil) {
        this.stateEventUtil = stateEventUtil;
    }
}

接口控制器

定义接口控制器,提供测试接口:

@RestController
public class OrderController {

    private IOrderService orderService;

    @GetMapping("testOrderStatusMachine")
    public void testOrderStatusMachine(){
        Long orderId1 = orderService.createOrder(new OrderDO());
        Long orderId2 = orderService.createOrder(new OrderDO());

        orderService.confirmOrder(orderId1);
        new Thread("客户线程"){
            @Override
            public void run() {
                orderService.deliver(orderId1);
                orderService.signOrder(orderId1);
                orderService.finishOrder(orderId1);
            }
        }.start();

        orderService.confirmOrder(orderId2);
        orderService.deliver(orderId2);
        orderService.signOrder(orderId2);
        orderService.finishOrder(orderId2);

        System.out.println("全部订单状态:" + orderService.listOrders());
    }

    @Autowired
    public void setOrderService(IOrderService orderService) {
        this.orderService = orderService;
    }
}

运行效果展示

调用接口后,可以看到订单状态在状态机的控制下流转的过程。日志输出表明订单状态的变化是符合预期的,状态机工作正常。

注意事项与最佳实践

  1. 一致性保证:确保状态机的配置正确反映了业务逻辑,并保持其在并发环境下的状态一致性。
  2. 异常处理:在状态转换过程中可能出现异常情况,需要适当地捕获和处理这些异常,防止状态机进入无效状态。
  3. 监控与审计:在实际应用中,为了便于调试和追溯,可以集成日志记录或事件监听器来记录状态机的每一次状态变迁。
  4. 扩展性与维护性:随着业务的发展,状态机的设计应当具有足够的灵活性,以便于新增状态或调整转换规则。
  5. 持久化机制:在生产环境中,为了保证系统的可靠性,应当实现稳健的状态持久化机制,如使用数据库或分布式缓存。

其他状态机实现方案

除了使用Spring State Machine这样的专门工具外,还可以使用其他方法实现状态机功能:

消息队列方式

状态的变更通过发布和消费消息来驱动。每当发生状态变更所需的事件时,生产者将事件作为一个消息发布到特定的消息队列(Topic),而消费者则监听这些消息,根据消息内容和业务规则对订单状态进行更新。这种方式有利于解耦各个服务,实现异步处理,同时增强系统的伸缩性和容错能力。

定时任务驱动

使用定时任务定期检查系统中的订单状态,根据预设的业务规则判断是否满足状态变迁条件。例如,每隔一段时间执行一次Job,查询数据库中处于特定状态的订单,并决定是否进行状态更新。这种方法适用于具有一定时效性的状态变迁,但实时性相对较低,对于瞬时响应要求高的场景不太适用。

规则引擎方式

利用规则引擎(如Drools、LiteFlow等)实现状态机,业务团队可以直接在规则引擎中定义状态及状态之间的转换规则,当新的事实数据(如订单信息)输入到规则引擎时,引擎会自动匹配并执行相应的规则,触发状态改变。这种方式的优点在于业务规则高度集中,易于管理和修改,同时也具备较高的灵活性,能够快速应对业务规则的变化。

项目结构

以下是完整的项目结构,方便理解各个组件之间的关系:

src/main/java/com/example/statemachine/
├── config
│   ├── OrderPersist.java             // 状态机持久化配置
│   └── OrderStatusMachineConfig.java // 状态机状态和转换配置
├── controller
│   └── OrderController.java          // 接口控制器
├── entity
│   └── OrderDO.java                  // 订单实体
├── enums
│   ├── OrderStatusEnum.java          // 订单状态枚举
│   └── OrderStatusOperateEventEnum.java // 订单状态操作事件枚举
├── listener
│   └── OrderStatusListener.java      // 状态监听器
├── service
│   ├── IOrderService.java            // 订单服务接口
│   └── impl
│       └── OrderServiceImpl.java     // 订单服务实现
└── util
    └── StateEventUtil.java           // 状态事件工具类

总结

状态机是一种强大的设计模式,它可以帮助我们有效地管理系统中的状态转换逻辑。Spring State Machine提供了一个完善的框架来实现这种模式,特别适合于订单处理、工作流引擎等需要复杂状态管理的场景。

通过本文的实践,我们了解了如何使用Spring State Machine来实现订单状态的流转,包括状态机的配置、状态转换的触发、状态的持久化以及状态监听器的使用。同时,我们也探讨了其他实现状态机功能的方法,如消息队列、定时任务和规则引擎等,这些方法各有优缺点,可以根据实际业务需求选择合适的实现方式。

无论选择哪种实现方式,关键是保持代码的清晰结构和良好的可维护性,确保状态转换逻辑的正确性和一致性,这样才能够在复杂的业务场景中有效地管理系统状态。

你可能感兴趣的:(设计模式,设计模式,spring,java,后端,架构)