作为一名程序员,追求代码的简洁和高效是本能。我曾坚信,代码越直观越可靠,因此一度对“流程编排”这类设计模式持怀疑态度——这不就是典型的过度设计吗?
直到我加入一个业务中台团队,面对需要接入十几个不同业务方的复杂场景,我才深刻体会到,流程编排能力简直是“保命”的刚需。当每个业务方都有独特的差异化逻辑,如果没有良好的架构设计,代码里很快就会充斥着难以维护的 if-else 分支。
if (biz == BizA || biz == BizB) {
//do some thing
//这部分逻辑相同
if (biz == BizA) {
//差异化处理
}
if (biz == BizB) {
//差异化逻辑
}
}
想象一下,十几个业务线交织在一起,任何改动都可能引发“牵一发而动全身”的蝴蝶效应。要求测试回归全部业务逻辑几乎不可能,而开发者则深陷在千丝万缕的代码“屎山”中寻找目标逻辑,稍有不慎就会引发线上故障。
解决这类代码隔离性和业务扩展性问题的核心手段有两个:
- 使用流程引擎,为不同的业务配置不同的流程执行链。
- 使用插件扩展引擎,让不同的业务自行实现差异化部分。
在开源的会员交易解决方案项目 MemberClub 中,就大量运用了这两种设计思想。接下来,我们以该项目为例,看看如何利用流程引擎优雅地解决复杂业务耦合问题。
配置流程执行链
考虑到不同会员产品的交易流程存在差异,可以为不同产品配置独立的流程链。在 DemoMemberPurchaseExtension 扩展点中,定义了三种流程执行链的配置方式。

通过 FlowChain.newChain() 方法,可以清晰地构建出包含多个节点的流程链,例如购买提单链就依次包含了锁单、校验商品、检查库存、创建订单、扣减库存等一系列节点。这种配置方式让业务流程一目了然,并且可以按产品线进行灵活定制。
定义流程节点
每个流程节点是一个独立的类,继承自 FlowNode<T>,并通常实现四个核心方法:process、success、rollback 和 callback。
@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) 方法即可。

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

- 顺序执行:依次执行每个流程节点的
process 方法。
- 异常回滚:若某个
process 方法执行失败,则引擎会捕获异常,并逆向执行已成功节点的 rollback 方法进行回滚。
- 成功回调:若所有
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实战架构思想和开源项目剖析,欢迎在云栈社区与我们继续探讨。