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_ORDER# 2. 发起支付(触发待支付→已支付)POST /orders/123/events?event=INITIATE_PAYMENT# 3. 发货(触发已支付→已发货)POST /orders/123/events?event=SHIP_ORDER# 4. 确认送达(触发已发货→已送达)POST /orders/123/events?event=DELIVERY_CONFIRMED# 5. 取消订单(触发新订单/待支付→已取消)POST /orders/123/events?event=CANCEL_ORDER
11
10. 体系核心优势
-
1. 状态流转规范化:基于Spring StateMachine,状态变更规则集中配置,避免散列的if-else硬编码; -
2. 插件化可扩展:核心逻辑与业务插件解耦,新增功能只需实现接口,无需修改原有代码; -
3. 事件驱动架构:状态变更由事件触发,逻辑清晰,便于问题定位和扩展; -
4. 关注点分离:状态机管流转、插件管业务、监听器管通知,各组件职责单一; -
5. 易测试易维护:接口化设计让单元测试更简单,组件替换不影响整体体系。本实现可直接落地到实际项目,也可根据业务需求扩展更多状态、事件和插件(比如退款、售后等场景)。
1.CICD+Docker+Dockerfile三大系列37篇系统讲解
3.RabbitMQ+MySQL30篇两大系列讲解
夜雨聆风