乐于分享
好东西不私藏

Spring高级开发:状态机/事件/插件

Spring高级开发:状态机/事件/插件

01

在后端业务开发中,订单、工单这类有明确状态流转的场景非常常见。Spring StateMachine(Spring状态机)是处理状态流转的绝佳工具,它能规范化状态变更逻辑、降低硬编码耦合度。本文会以订单处理系统为实战案例,完整演示Spring状态机的配置、事件驱动机制落地,以及可灵活扩展的插件体系搭建。

02

1. 基础依赖准备(pom.xml)

首先需要引入Spring状态机核心依赖,以及Spring上下文支持依赖,确保项目能正常加载状态机和插件体系:

<dependencies>    <!-- Spring状态机核心启动依赖 -->    <dependency>        <groupId>org.springframework.statemachine</groupId>        <artifactId>spring-statemachine-starter</artifactId>        <version>4.2.0</version>    </dependency>    <!-- Spring上下文扩展支持,用于插件和监听器的管理 -->    <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-context-support</artifactId>        <version>6.0.9</version>    </dependency></dependencies>

03

2. 核心接口与枚举定义

2.1 订单状态与事件枚举

先定义订单的核心状态和触发状态变更的事件,这是状态机的基础:

/** * 订单状态枚举 * 覆盖订单从创建到完成/取消的全生命周期 */public enum OrderState {    NEW,             // 新订单(初始状态)    PAYMENT_PENDING, // 待支付    PAID,            // 已支付    SHIPPED,         // 已发货    DELIVERED,       // 已送达(结束状态)    CANCELLED        // 已取消(结束状态)}/** * 订单事件枚举 * 每个事件对应一次状态变更的触发动作 */public enum OrderEvent {    CREATE_ORDER,        // 创建订单(触发新订单→待支付)    INITIATE_PAYMENT,    // 发起支付(触发待支付→已支付)    PAYMENT_COMPLETED,   // 支付完成(预留扩展事件)    SHIP_ORDER,          // 发货(触发已支付→已发货)    DELIVERY_CONFIRMED,  // 确认送达(触发已发货→已送达)    CANCEL_ORDER         // 取消订单(触发新订单/待支付→已取消)}

2.2 插件体系核心接口

为了让状态机具备可扩展能力,定义插件和监听器接口,实现业务逻辑与状态机解耦:

/** * 状态变更监听器接口 * 监听订单状态变更,可用于审计、日志等场景 */public interface StateChangeListener {    /**     * 状态变更回调方法     * @param from 变更前状态     * @param to 变更后状态     * @param orderId 订单ID     */    void onStateChange(OrderState from, OrderState to, String orderId);}/** * 订单操作插件接口 * 可针对不同订单状态执行自定义业务逻辑 */public interface OrderOperationPlugin {    /**     * 插件执行方法     * @param orderId 订单ID     * @param currentState 订单当前状态     */    void execute(String orderId, OrderState currentState);}/** * 插件管理器接口 * 统一管理监听器注册、状态变更通知、插件执行 */public interface PluginManager {    // 注册状态变更监听器    void registerStateChangeListener(StateChangeListener listener);    // 通知所有监听器:订单状态已变更    void notifyStateChange(OrderState from, OrderState to, String orderId);    // 执行所有已注册的订单操作插件    void executePlugins(String orderId, OrderState currentState);}

04

3. Spring状态机核心配置

通过配置类定义状态机的状态集、状态流转规则,同时集成插件管理器:

import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;import java.util.List;/** * 订单状态机配置类 * 定义状态集、状态流转规则,关联插件管理器 */public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderState, OrderEvent> {    // 注入订单操作插件列表    private List<OrderOperationPlugin> plugins;    /**     * 配置状态机的状态集     */    @Override    public void configure(StateMachineStateConfigurer<OrderState, OrderEvent> states) throws Exception {        states            .withStates()            .initial(OrderState.NEW)          // 设置初始状态为"新订单"            .state(OrderState.PAYMENT_PENDING)// 普通状态:待支付            .junction(OrderState.PAID)        // 分支状态:已支付(可扩展多分支流转)            .end(OrderState.DELIVERED)        // 结束状态:已送达            .end(OrderState.CANCELLED)        // 结束状态:已取消            .fork(OrderState.SHIPPED);        // 分叉状态:已发货(可扩展并行处理)    }    /**     * 配置状态流转规则(事件触发状态变更)     */    @Override    public void configure(StateMachineTransitionConfigurer<OrderState, OrderEvent> transitions) throws Exception {        transitions            // 新订单 → 待支付(触发事件:创建订单)            .withExternal()                .source(OrderState.NEW).target(OrderState.PAYMENT_PENDING)                .event(OrderEvent.CREATE_ORDER)            .and().withExternal()                // 待支付 → 已支付(触发事件:发起支付)                .source(OrderState.PAYMENT_PENDING).target(OrderState.PAID)                .event(OrderEvent.INITIATE_PAYMENT)            .and().withExternal()                // 已支付 → 已发货(触发事件:发货)                .source(OrderState.PAID).target(OrderState.SHIPPED)                .event(OrderEvent.SHIP_ORDER)            .and().withExternal()                // 已发货 → 已送达(触发事件:确认送达)                .source(OrderState.SHIPPED).target(OrderState.DELIVERED)                .event(OrderEvent.DELIVERY_CONFIRMED)            .and().withExternal()                // 新订单 → 已取消(触发事件:取消订单)                .source(OrderState.NEW).target(OrderState.CANCELLED)                .event(OrderEvent.CANCEL_ORDER)            .and().withExternal()                // 待支付 → 已取消(触发事件:取消订单)                .source(OrderState.PAYMENT_PENDING).target(OrderState.CANCELLED)                .event(OrderEvent.CANCEL_ORDER);    }    /**     * 初始化插件管理器(交给Spring容器管理)     * @return 插件管理器实例     */    public PluginManager pluginManager() {        return new DefaultPluginManager(plugins);    }}

05

4. 插件体系落地实现

4.1 默认插件管理器(核心实现)

实现插件管理器接口,统一管理监听器和插件的执行:

import java.util.ArrayList;import java.util.List;/** * 默认插件管理器实现类 * 负责监听器注册、状态变更通知、插件批量执行 */public class DefaultPluginManager implements PluginManager {    // 状态变更监听器列表    private final List<StateChangeListener> stateChangeListeners = new ArrayList<>();    // 订单操作插件列表    private final List<OrderOperationPlugin> operationPlugins;    // 构造函数:注入插件列表    public DefaultPluginManager(List<OrderOperationPlugin> plugins) {        this.operationPlugins = plugins;    }    /**     * 注册状态变更监听器     */    @Override    public void registerStateChangeListener(StateChangeListener listener) {        stateChangeListeners.add(listener);    }    /**     * 状态变更通知:遍历所有监听器执行回调     */    @Override    public void notifyStateChange(OrderState from, OrderState to, String orderId) {        stateChangeListeners.forEach(listener -> listener.onStateChange(from, to, orderId));    }    /**     * 执行所有插件:遍历插件列表执行自定义逻辑     */    @Override    public void executePlugins(String orderId, OrderState currentState) {        operationPlugins.forEach(plugin -> plugin.execute(orderId, currentState));    }}

4.2 实战插件实现(示例)

基于插件接口实现具体业务插件,可按需扩展,不侵入核心状态机逻辑:

/** * 日志插件 * 记录订单状态变更的日志信息 */public class LoggingPlugin implements OrderOperationPlugin {    @Override    public void execute(String orderId, OrderState currentState) {        System.out.println("【日志插件】订单 " + orderId + " 当前状态: " + currentState + " - 已记录状态日志");    }}/** * 邮件通知插件 * 针对订单状态变更发送邮件提醒 */public class EmailNotificationPlugin implements OrderOperationPlugin {    @Override    public void execute(String orderId, OrderState currentState) {        System.out.println("【邮件插件】订单 " + orderId + " 当前状态: " + currentState + " - 已发送邮件通知");    }}/** * 库存更新插件 * 仅在订单"已支付"状态时更新库存 */public class InventoryUpdatePlugin implements OrderOperationPlugin {    @Override    public void execute(String orderId, OrderState currentState) {        // 仅处理"已支付"状态的库存更新逻辑        if (currentState == OrderState.PAID) {            System.out.println("【库存插件】订单 " + orderId + " 已支付,正在扣减对应商品库存");        }    }}

06

5. 状态变更监听器实现

实现状态变更监听器,用于审计订单状态变更记录:

/** * 审计监听器 * 记录订单状态变更的审计日志,用于追溯和合规检查 */public class AuditStateChangeListener implements StateChangeListener {    @Override    public void onStateChange(OrderState from, OrderState to, String orderId) {        System.out.println("【审计监听器】订单状态变更: " + orderId + " 从 " + from + " 变更为 " + to + " - 审计记录已生成");    }}

07

6. 服务层封装(业务入口)

封装订单服务,作为状态机和插件体系的业务入口,对外提供统一的事件处理能力:

import org.springframework.statemachine.StateMachine;/** * 订单服务 * 封装状态机操作、事件处理、插件执行逻辑 */public class OrderService {    // 注入Spring状态机实例    private StateMachine<OrderState, OrderEvent> stateMachine;    // 注入插件管理器    private PluginManager pluginManager;    /**     * 构造函数:初始化监听器     */    public OrderService() {        // 注册审计监听器(可按需注册多个)        pluginManager.registerStateChangeListener(new AuditStateChangeListener());    }    /**     * 处理订单事件(核心方法)     * @param orderId 订单ID     * @param event 要触发的订单事件     */    public void handleOrderEvent(String orderId, OrderEvent event) {        try {            // 启动状态机            stateMachine.start();            // 获取当前状态            OrderState currentState = stateMachine.getState().getId();            // 发送事件,触发状态变更            stateMachine.sendEvent(event);            // 获取变更后的新状态            OrderState newState = stateMachine.getState().getId();            // 如果状态发生变更,通知所有监听器            if (currentState != newState) {                pluginManager.notifyStateChange(currentState, newState, orderId);            }            // 执行所有插件的业务逻辑            pluginManager.executePlugins(orderId, newState);        } catch (Exception e) {            // 异常捕获:记录错误日志            System.err.println("处理订单事件失败,订单ID:" + orderId + ",错误信息:" + e.getMessage());        } finally {            // 停止状态机,释放资源            stateMachine.stop();        }    }}

08

7. 控制器层(接口暴露)

通过控制器对外暴露HTTP接口,接收前端/外部系统的事件触发请求:

import org.springframework.http.ResponseEntity;/** * 订单控制器 * 对外提供订单事件处理、状态查询接口 */public class OrderController {    // 注入订单服务    private OrderService orderService;    /**     * 触发订单事件接口     * @param orderId 订单ID     * @param event 事件名称(字符串类型,需转换为枚举)     * @return 处理结果     */    public ResponseEntity<String> sendEvent(String orderId, String event) {        try {            // 将字符串事件转换为枚举(统一大小写)            OrderEvent orderEvent = OrderEvent.valueOf(event.toUpperCase());            // 调用订单服务处理事件            orderService.handleOrderEvent(orderId, orderEvent);            return ResponseEntity.ok("事件处理成功:" + event);        } catch (IllegalArgumentException e) {            // 事件类型无效时返回400错误            return ResponseEntity.badRequest().body("无效的事件类型:" + event);        }    }    /**     * 查询订单状态接口     * @param orderId 订单ID     * @return 订单当前状态     */    public ResponseEntity<String> checkStatus(String orderId) {        // 实际场景中需从状态机/数据库获取真实状态,此处为示例        String status = "示例状态(实际需对接状态机/数据库)";        return ResponseEntity.ok("订单 " + orderId + " 当前状态: " + status);    }}

09

8. 体系扩展说明(灵活扩展)

8.1 新增插件

只需实现OrderOperationPlugin接口,无需修改核心代码,符合开闭原则

/** * 新功能插件示例 * 可按需扩展任意业务逻辑,比如积分发放、优惠券核销等 */public class NewFeaturePlugin implements OrderOperationPlugin {    @Override    public void execute(String orderId, OrderState currentState) {        // 示例:订单送达后发放积分        if (currentState == OrderState.DELIVERED) {            System.out.println("【新功能插件】订单 " + orderId + " 已送达,为用户发放100积分");        }    }}

8.2 新增状态监听器

实现StateChangeListener接口,即可监听状态变更,比如对接消息队列、数据同步等:

/** * 新状态监听器示例 * 可用于状态变更后的异步通知、数据同步等场景 */public class NewStateChangeListener implements StateChangeListener {    @Override    public void onStateChange(OrderState from, OrderState to, String orderId) {        // 示例:订单取消后同步到风控系统        if (to == OrderState.CANCELLED) {            System.out.println("【新监听器】订单 " + orderId + " 已取消,同步数据到风控系统");        }    }}

10

9. 实际使用示例(接口调用)

通过HTTP请求触发订单事件,对应实际业务场景的接口调用:

1. 创建订单(触发新订单→待支付)POST /orders/123/events?event=CREATE_ORDER2. 发起支付(触发待支付→已支付)POST /orders/123/events?event=INITIATE_PAYMENT3. 发货(触发已支付→已发货)POST /orders/123/events?event=SHIP_ORDER4. 确认送达(触发已发货→已送达)POST /orders/123/events?event=DELIVERY_CONFIRMED5. 取消订单(触发新订单/待支付→已取消)POST /orders/123/events?event=CANCEL_ORDER

11

10. 体系核心优势

  1. 1. 状态流转规范化:基于Spring StateMachine,状态变更规则集中配置,避免散列的if-else硬编码;
  2. 2. 插件化可扩展:核心逻辑与业务插件解耦,新增功能只需实现接口,无需修改原有代码;
  3. 3. 事件驱动架构:状态变更由事件触发,逻辑清晰,便于问题定位和扩展;
  4. 4. 关注点分离:状态机管流转、插件管业务、监听器管通知,各组件职责单一;
  5. 5. 易测试易维护:接口化设计让单元测试更简单,组件替换不影响整体体系。本实现可直接落地到实际项目,也可根据业务需求扩展更多状态、事件和插件(比如退款、售后等场景)。
推荐文章:

1.CICD+Docker+Dockerfile三大系列37篇系统讲解

2.《剑指Offer》刷题笔记66篇

3.RabbitMQ+MySQL30篇两大系列讲解