找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3102

积分

0

好友

424

主题
发表于 昨天 06:40 | 查看: 3| 回复: 0

作为一名程序员,追求代码的简洁和高效是本能。我曾坚信,代码越直观越可靠,因此一度对“流程编排”这类设计模式持怀疑态度——这不就是典型的过度设计吗?

直到我加入一个业务中台团队,面对需要接入十几个不同业务方的复杂场景,我才深刻体会到,流程编排能力简直是“保命”的刚需。当每个业务方都有独特的差异化逻辑,如果没有良好的架构设计,代码里很快就会充斥着难以维护的 if-else 分支。

if (biz == BizA || biz == BizB) {
    //do some thing
    //这部分逻辑相同
    if (biz == BizA) {
        //差异化处理
    }
    if (biz == BizB) {
        //差异化逻辑
    }
}

想象一下,十几个业务线交织在一起,任何改动都可能引发“牵一发而动全身”的蝴蝶效应。要求测试回归全部业务逻辑几乎不可能,而开发者则深陷在千丝万缕的代码“屎山”中寻找目标逻辑,稍有不慎就会引发线上故障。

解决这类代码隔离性业务扩展性问题的核心手段有两个:

  1. 使用流程引擎,为不同的业务配置不同的流程执行链。
  2. 使用插件扩展引擎,让不同的业务自行实现差异化部分。

在开源的会员交易解决方案项目 MemberClub 中,就大量运用了这两种设计思想。接下来,我们以该项目为例,看看如何利用流程引擎优雅地解决复杂业务耦合问题。

配置流程执行链

考虑到不同会员产品的交易流程存在差异,可以为不同产品配置独立的流程链。在 DemoMemberPurchaseExtension 扩展点中,定义了三种流程执行链的配置方式。

DemoMemberPurchaseExtension扩展点代码,展示了购买交易提单、逆向、取消三个流程链的配置

通过 FlowChain.newChain() 方法,可以清晰地构建出包含多个节点的流程链,例如购买提单链就依次包含了锁单、校验商品、检查库存、创建订单、扣减库存等一系列节点。这种配置方式让业务流程一目了然,并且可以按产品线进行灵活定制。

定义流程节点

每个流程节点是一个独立的类,继承自 FlowNode<T>,并通常实现四个核心方法:processsuccessrollbackcallback

@Service
public class PurchaseSubmitLockFlow extends FlowNode<PurchaseSubmitContext> {
    @Autowired
    private MemberTradeLockService memberTradeLockService;

    @Override
    public void process(PurchaseSubmitContext context) {
        memberTradeLockService.lockOnPrePurchase(context);
    }

    @Override
    public void success(PurchaseSubmitContext context) {
        memberTradeLockService.unlockOnPurchaseSuccess(context);
    }

    @Override
    public void rollback(PurchaseSubmitContext context, Exception e) {
        memberTradeLockService.unlockOnPurchaseFail(context);
    }

    @Override
    public void callback(PurchaseSubmitContext context, Exception e) {
    }
}

如上图的 PurchaseSubmitLockFlow 节点所示,process 方法执行核心逻辑(加锁),success 方法处理成功后的善后(取消锁),rollback 方法则在发生异常时执行回滚操作(异常取消锁)。这种设计完美支持了事务性操作。

流程执行

在业务接口中,执行流程变得异常简洁。只需准备好流程上下文对象,然后调用 FlowChain.execute(context) 方法即可。

流程执行接口代码,分别调用submitChain和purchaseReverseChain的execute方法

流程引擎执行原理

流程引擎的核心工作原理类似于责任链模式,但增加了完善的成功回调和异常回滚机制。具体执行顺序如下图所示:

会员购买提单流程执行图,展示了各个节点process、success、rollback方法的执行顺序与异常回滚路径

  1. 顺序执行:依次执行每个流程节点的 process 方法。
  2. 异常回滚:若某个 process 方法执行失败,则引擎会捕获异常,并逆向执行已成功节点的 rollback 方法进行回滚。
  3. 成功回调:若所有 process 方法均执行成功,则引擎会逆向执行每个节点的 success 方法进行后续处理。

以下是 FlowChain.execute 方法的核心逻辑代码:

public <T> void execute(FlowChain<T> chain, T context) {
    Exception exception = null;
    int index = -1;
    for (FlowNode<T> node : chain.getNodes()) {
        try {
            node.process(context);
            index++;
        } catch (Exception e) {
            if (e instanceof SkipException) {
                CommonLog.warn("当前流程:{} 发出 Skip请求,后续流程不再执行", node.getClass().getSimpleName());
                break;
            }
            exception = e;
            break;
        }
    }

    if (exception != null) {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.rollback(context, exception);
            } catch (Exception e) {
                CommonLog.error("rollback执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
            }
        }
    } else {
        for (int i = index; i >= 0; i--) {
            FlowNode<T> node = chain.getNodes().get(i);
            try {
                node.success(context);
            } catch (Exception e) {
                CommonLog.error("success 执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
            }
        }
    }

    for (int i = index; i >= 0; i--) {
        FlowNode<T> node = chain.getNodes().get(i);
        try {
            node.callback(context, exception);
        } catch (Exception e) {
            CommonLog.error("callback执行异常,忽略 name:{}", node.getClass().getSimpleName(), e);
        }
    }
    if (exception != null) {
        throw exception;
    }
}

完整的流程引擎源码可以在 MemberClub 项目的以下路径找到:

https://gitee.com/-/ide/project/juejinwuyang/memberclub/edit/master/-/memberclub.common/src/main/java/com/memberclub/common/flow/FlowChainService.java

关于 MemberClub 项目

MemberClub 是一个托管在 Gitee 的开源项目,它提供了一个完整的付费会员交易解决方案,涵盖各类购买场景下的履约及售后结算能力。这是一个非常好的学习业务中台设计和后端架构思想的项目。

通过这个项目,你可以学习到 SpringBoot 如何集成以下主流框架和组件:

  • Mybatis-plus
  • Sharding-sphere 多数据源分库分表
  • Redis/redisson
  • Apollo
  • Springcloud(feign/eureka)
  • RabbitMQ
  • H2 内存数据库
  • Swagger
  • Lombok+MapStruct

同时,你还可以深入理解以下核心组件的实现原理:

  • 流程引擎
  • 扩展点引擎
  • 分布式重试组件
  • 通用日志组件
  • 商品库存设计
  • 分布式锁组件
  • Redis Lua 脚本的使用
  • Spring 上下文工具类

GitHub开源地址:

https://github.com/juejin-wuyang/memberclub

总结

从最初的排斥到如今的推崇,我对流程编排技术的认知转变源于真实的复杂业务场景。它并非为了炫技,而是解决多业务线并行开发、维护与隔离痛点的务实架构选择。通过将业务流程模块化、节点化,并利用引擎统一调度,我们能够实现:

  • 代码隔离:不同业务的逻辑互不干扰。
  • 灵活扩展:新增业务只需配置或新增节点,无需修改主干逻辑。
  • 可维护性:流程清晰可见,降低理解和调试成本。
  • 事务支持:内置的成功/回滚机制保障了业务操作的原子性。

如果你也正在为复杂的业务逻辑和纠缠的 if-else 而苦恼,不妨深入研究一下流程编排和插件化设计,或许它能为你打开一扇新的大门。对于更多类似的Java实战架构思想和开源项目剖析,欢迎在云栈社区与我们继续探讨。




上一篇:LobsterAI评测:网易有道的开源桌面智能体,能否成为OpenClaw的国产平替?
下一篇:C++面试高频题:struct与class区别详解及其设计哲学与工程实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-23 10:26 , Processed in 0.566007 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表