在这里插入图片描述

肖哥弹架构 跟大家“弹弹” Spring Statemachine设计与实战应用,需要代码关注

欢迎 点赞,关注,转发。

关注公号Solomon肖哥弹架构获取更多精彩内容

历史热点文章

本文探讨Spring Statemachine的高级功能,涵盖状态机服务、拦截器、监听器、错误处理及持久化等核心模块。主要内容包括:

  1. 状态机服务:通过缓存和对象池优化实例管理,解决资源隔离与并发控制问题;
  2. 拦截器与监听器:对比两者的差异,实现流程控制、审计日志和安全校验;
  3. 错误处理机制:提供全局监听、异常处理器等方案,保障状态一致性;
  4. 持久化实践:自定义存储库支持Redis、加密存储等场景,详解StateMachinePersistStateMachineRuntimePersister的协作。

1. 状态机服务(StateMachineService)

在这里插入图片描述

状态机服务是对Spring Statemachine核心功能的高层抽象封装,提供统一的状态机生命周期管理和访问控制。它作为应用层与状态机框架之间的中间层,简化状态机的使用复杂度。

1.1 状态机服务的核心职责
  1. 生命周期管理:统一管理状态机的创建、启动、停止和销毁
  2. 实例存取控制:提供状态机实例的获取和释放机制
  3. 资源隔离:确保不同业务场景使用独立的状态机实例
  4. 性能优化:通过缓存/池化技术减少重复创建开销
1.2 解决的关键问题
问题类型 传统方式痛点 状态机服务方案
实例管理混乱 直接使用StateMachineFactory导致实例散落各处 集中式存储管理
资源泄漏风险 需手动调用stop()释放资源 提供release自动清理
并发访问冲突 多线程共享同一状态机实例 线程隔离或同步控制
配置一致性 每次getStateMachine()可能返回新实例 保证配置相同的机器ID返回同一实例
1.3 服务设计实现方案
1.3.1 基础版本(带简单缓存)
/**
 * 状态机服务实现(基于缓存机制)
 * 
 * 核心职责:
 * 1. 统一管理状态机实例的生命周期
 * 2. 提供线程安全的状态机存取
 * 3. 避免重复创建相同配置的状态机
 * 
 * 设计特点:
 * - 使用ConcurrentHashMap实现线程安全缓存
 * - 通过@Transactional支持事务边界
 * - 实现PreDestroy确保资源清理
 */
@Service
public class StateMachineServiceImpl implements StateMachineService {

    // 注入状态机工厂(由Spring自动配置)
    @Autowired
    private StateMachineFactory<String, String> factory;

    // 状态机实例缓存(Key: machineId, Value: 状态机实例)
    private final Map<String, StateMachine<String, String>> machineCache = 
        new ConcurrentHashMap<>();

    /**
     * 获取状态机实例(缓存优先)
     * 
     * @param machineId 状态机唯一标识
     * @return 已初始化的状态机实例
     * 
     * @Transactional注解确保:
     * 1. 方法执行在事务上下文中
     * 2. 状态机操作可参与事务(需配合持久化配置)
     */
    @Override
    @Transactional
    public StateMachine<String, String> getMachine(String machineId) {
        return machineCache.computeIfAbsent(machineId, id -> {
            // 缓存未命中时创建新实例
            StateMachine<String, String> machine = factory.getStateMachine(id);
            
            // 启动状态机(触发初始状态转换)
            machine.start();
            
            // 将新实例放入缓存
            return machine;
        });
    }

    /**
     * 释放状态机资源
     * 
     * @param machineId 要释放的状态机ID
     * 
     * 注意:
     * - 必须显式调用以避免内存泄漏
     * - 典型场景:业务流程结束时调用
     */
    @Override
    public void releaseMachine(String machineId) {
        StateMachine<String, String> machine = machineCache.remove(machineId);
        if (machine != null && machine.isRunning()) {
            // 停止状态机(释放内部资源)
            machine.stop();
        }
    }

    /**
     * 容器销毁前的清理钩子
     * 
     * 确保:
     * 1. 所有状态机实例被正确停止
     * 2. 缓存清空帮助GC回收
     */
    @PreDestroy
    public void destroy() {
        machineCache.values().forEach(machine -> {
            if (machine.isRunning()) {
                machine.stop();
            }
        });
        machineCache.clear();
    }

    // ---- 可选增强功能 ----
    
    /**
     * 获取当前缓存状态(监控用)
     */
    public Map<String, String> getCacheStatus() {
        Map<String, String> status = new HashMap<>();
        machineCache.forEach((id, machine) -> {
            status.put(id, machine.getState().toString());
        });
        return status;
    }
}
1.3.2 高级版本(带对象池)
/**
 * 基于对象池的状态机服务实现
 * 
 * 核心功能:
 * 1. 管理状态机实例的生命周期(创建/销毁)
 * 2. 通过对象池复用状态机实例,降低创建开销
 * 3. 提供线程安全的状态机存取服务
 * 
 * 适用场景:
 * - 高频使用状态机的并发环境
 * - 需要严格控制资源占用的场景
 */
@Service
public class PooledStateMachineService {

    // 使用Apache Commons Pool2实现的对象池
    private final GenericObjectPool<StateMachine<String, String>> pool;

    /**
     * 构造函数(依赖注入StateMachineFactory)
     * 
     * @param factory 状态机工厂,用于创建新的状态机实例
     */
    public PooledStateMachineService(StateMachineFactory