责任链模式实现流程动态编排

如何使用责任链设计模式 + 事务 + 回滚 + 异步 + 监控 + 可中断等实现业务流程动态编排

适用场景:

  • 电商订单流程(校验→锁库存→扣减→支付→物流)
  • 审批流程(申请人→部门经理→HR→财务)
  • 风控/审核流程
  • 可动态调整步骤顺序、增删节点

一、核心思想

  1. 每个业务步骤 = 一个独立处理器(Handler)
  2. 处理器之间形成链式调用
  3. 流程顺序不写死在代码,可配置(数据库/JSON/YAML)
  4. 支持中断、跳过、异常回滚
  5. 可热插拔:新增步骤只需新增类,无需修改主流程

示例整体结构

  1. FlowContext ------ 流程上下文(携带数据、状态、标记)
  2. FlowHandler ------ 标准处理器接口(handle + rollback + getName)
  3. AbstractFlowHandler ------ 抽象链(自动管理 next、统一异常、统一监控)
  4. FlowEngine ------ 流程引擎(动态构建责任链)
  5. 业务处理器 ------ 校验/锁库存/支付/发货(可插拔)
  6. 事务 + 回滚 ------ 某一步失败,前面步骤自动回滚
  7. 异步 + 监控 ------ 计时、日志、告警

1. 流程上下文(贯穿全链)

java 复制代码
@Data
public class FlowContext {

    // 业务标识
    private String orderId;
    private Long userId;

    // 流程控制
    private boolean breakFlow = false;
    private String errorMsg;

    // 事务/回滚使用:记录已执行节点
    private List<String> executedHandlers = new ArrayList<>();

    // 扩展数据
    private Map<String, Object> data = new HashMap<>();
}

2. 标准处理器接口(含回滚)

java 复制代码
public interface FlowHandler {

    /**
     * 执行节点
     */
    void handle(FlowContext context);

    /**
     * 回滚节点(事务失败时)
     */
    void rollback(FlowContext context);

    /**
     * 节点唯一名称
     */
    String getName();
}

3. 抽象链实现(核心:异常、监控、next、中断)

java 复制代码
public abstract class AbstractFlowHandler implements FlowHandler {

    protected FlowHandler next;

    public void setNext(FlowHandler next) {
        this.next = next;
    }

    @Override
    public final void handle(FlowContext context) {
        if (context.isBreakFlow()) {
            fireNext(context);
            return;
        }

        String handlerName = getName();
        Stopwatch stopwatch = Stopwatch.createStarted();

        try {
            // 执行业务逻辑
            doHandle(context);

            // 记录已执行,用于回滚
            context.getExecutedHandlers().add(handlerName);

        } catch (Exception e) {
            log.error("节点[{}]执行异常: {}", handlerName, e.getMessage());
            context.setBreakFlow(true);
            context.setErrorMsg(e.getMessage());
        } finally {
            log.info("节点[{}] 耗时: {}ms", handlerName, stopwatch.elapsed(TimeUnit.MILLISECONDS));
        }

        // 执行下一个
        fireNext(context);
    }

    /**
     * 子类实现真正业务
     */
    protected abstract void doHandle(FlowContext context);

    /**
     * 驱动下一个节点
     */
    protected void fireNext(FlowContext context) {
        if (next != null && !context.isBreakFlow()) {
            next.handle(context);
        }
    }
}

4. 业务节点示例(3 个可插拔节点)

4.1 订单校验

java 复制代码
@Component
public class OrderCheckHandler extends AbstractFlowHandler {

    @Override
    public String getName() {
        return "orderCheck";
    }

    @Override
    protected void doHandle(FlowContext context) {
        log.info("执行订单校验 orderId: {}", context.getOrderId());
        // 模拟失败
        // if (true) throw new RuntimeException("订单参数非法");
    }

    @Override
    public void rollback(FlowContext context) {
        log.info("回滚订单校验 orderId: {}", context.getOrderId());
    }
}

4.2 锁定库存

java 复制代码
@Component
public class StockLockHandler extends AbstractFlowHandler {

    @Override
    public String getName() {
        return "stockLock";
    }

    @Override
    protected void doHandle(FlowContext context) {
        log.info("执行锁定库存 orderId: {}", context.getOrderId());
    }

    @Override
    public void rollback(FlowContext context) {
        log.info("解锁库存 orderId: {}", context.getOrderId());
    }
}

4.3 支付扣款

java 复制代码
@Component
public class PayHandler extends AbstractFlowHandler {

    @Override
    public String getName() {
        return "pay";
    }

    @Override
    protected void doHandle(FlowContext context) {
        log.info("执行支付扣款 orderId: {}", context.getOrderId());
    }

    @Override
    public void rollback(FlowContext context) {
        log.info("支付退款 orderId: {}", context.getOrderId());
    }
}

5. 流程引擎(动态编排核心)

java 复制代码
@Component
public class FlowEngine {

    @Autowired
    private Map<String, FlowHandler> handlerMap;

    /**
     * 根据步骤列表构建责任链
     */
    public FlowHandler buildChain(List<String> handlerNames) {
        AbstractFlowHandler head = null;
        AbstractFlowHandler prev = null;

        for (String name : handlerNames) {
            FlowHandler handler = handlerMap.get(name);
            if (handler == null) {
                throw new RuntimeException("节点不存在: " + name);
            }

            AbstractFlowHandler current = (AbstractFlowHandler) handler;
            if (head == null) {
                head = current;
            } else {
                prev.setNext(current);
            }
            prev = current;
        }
        return head;
    }

    /**
     * 统一回滚已执行节点
     */
    public void rollback(FlowContext context) {
        List<String> executed = context.getExecutedHandlers();
        Collections.reverse(executed);

        for (String name : executed) {
            FlowHandler handler = handlerMap.get(name);
            if (handler != null) {
                try {
                    handler.rollback(context);
                } catch (Exception e) {
                    log.error("回滚节点[{}]异常", name, e);
                }
            }
        }
    }
}

6. 统一执行入口(带事务 + 异步 + 回滚)

java 复制代码
@Service
public class FlowService {

    @Autowired
    private FlowEngine flowEngine;

    @Autowired
    private ThreadPoolTaskExecutor asyncExecutor;

    /**
     * 同步执行流程
     */
    @Transactional(rollbackFor = Exception.class)
    public void executeFlow(List<String> handlerNames, FlowContext context) {
        FlowHandler chain = flowEngine.buildChain(handlerNames);
        chain.handle(context);

        // 失败自动回滚
        if (context.isBreakFlow()) {
            flowEngine.rollback(context);
            throw new RuntimeException(context.getErrorMsg());
        }
    }

    /**
     * 异步执行(生产推荐)
     */
    public CompletableFuture<Void> executeAsync(List<String> handlerNames, FlowContext context) {
        return CompletableFuture.runAsync(() -> {
            executeFlow(handlerNames, context);
        }, asyncExecutor);
    }
}

7. 控制器测试(动态编排任意流程)

java 复制代码
@RestController
@RequestMapping("/flow")
public class FlowController {

    @Autowired
    private FlowService flowService;

    @GetMapping("/start")
    public String start() {
        // 1. 构建上下文
        FlowContext context = new FlowContext();
        context.setOrderId("ORDER_" + System.currentTimeMillis());
        context.setUserId(1001L);

        // 2. 动态编排流程(可来自数据库)
        List<String> flow = Arrays.asList(
            "orderCheck",
            "stockLock",
            "pay"
        );

        // 3. 执行
        flowService.executeFlow(flow, context);
        return "执行完成";
    }
}

8. 总结

动态编排 :步骤顺序由配置/数据库决定,不写死

可插拔 :新增节点只加类,不改主流程

自动回滚 :任意节点失败,前面节点自动反向回滚

统一异常 :不抛裸异常,流程安全中断

统一监控 :每个节点自动计时、日志埋点

异步支持 :高并发不阻塞,不占用请求线程

事务保证 :Spring 事务控制,数据一致

可中断、可跳过、可重试

相关推荐
星原望野2 小时前
java:volatile关键字的作用
java·开发语言·volatile
XiYang-DING2 小时前
【Java】Map和Set
java·开发语言
菜菜小狗的学习笔记2 小时前
八股(二)Java集合
java·开发语言
星乐a2 小时前
String 不可变性与常量池深度解析
java·开发语言
captain3762 小时前
ACM模式下Java输入输出函数为什么会超时?及解决方法
java·开发语言
程序员老邢2 小时前
【产品底稿 04】商助慧 V1.1 里程碑:爬虫入库 + MySQL + Milvus 全链路打通
java·爬虫·mysql·ai·springboot·milvus
2601_950703942 小时前
Java安全编程与静态分析实战
java
好家伙VCC2 小时前
**发散创新:基于Python与OpenCV的视频流帧级分析实战**在当前人工智能与计算机视觉飞速发展的背景下
java·人工智能·python·计算机视觉
SimonKing2 小时前
大V说’AI替代不了你’,但现实是——用AI的人正在替代你
java·后端·程序员