说实话,if-else 写多了,真的有点上头。
尤其是在那种复杂业务流程一层套一层的项目里,页面流程一变,业务需求一加,代码就开始“如山倒”地冗长,真是改一行代码就像踩地雷,一不小心整个功能都塌了。你可能也遇到过这种情况:一个流程涉及十几个环节,每个环节都有一堆判断逻辑,流程改一下,十几个判断都要重新评估。
所以当我第一次看到 liteflow 这个规则引擎的时候,老实讲,我是带着一点点怀疑的。轻量级?高性能?还热部署?听起来有点像是“我全都要”的理想型框架。结果用了之后,竟然还真香了……
以前的 if-else,像是用胶水贴流程
我们先回忆一下常规写法,假设是一个订单支付完成后的流程,逻辑大概是这样的:
if (订单完成) {
发放积分();
发送MQ();
if (需要发短信) {
发送短信();
}
if (需要发邮件) {
发送邮件();
}
}
上面这只是最简单的示意,真正在业务里你会发现:每个逻辑块本身又是一堆判断,还要处理异常、中断、重试等等,维护成本直线上升。而且这东西最要命的是——流程的顺序、结构都写死了,任何变动,都得改代码。
用 liteflow 搞定流程,像是拼乐高
liteflow 是一个规则编排引擎,说人话就是:它允许你用配置规则的方式把流程节点像乐高一样拼接起来,再也不用死磕 if-else 了。
你可以把每个业务处理块抽象成一个“组件”,然后用 XML(也支持 JSON/YAML)来编排这些组件的执行顺序。
比如订单完成后的流程,在 liteflow 中的定义就是:
<chain name="order_finish_flow">
THEN(prepareTrade, grantScore, sendMq, WHEN(sendEmail, sendPhone))
</chain>
这串规则什么意思?串行执行:先准备交易、发积分、发消息,然后并行地发短信和发邮件。流程读起来清晰得跟念口诀一样,连新来的实习生看了都能大概懂什么意思。
而且你要是突然想加个“推送APP消息”的逻辑?只要把 sendAppNotify 加进 XML 就行,代码都不用动。
一个 Node,统一管理,统一调度
所有的业务逻辑,最终都会落到一个个 node(节点)上执行,而每个 node 就是一个 Java 类,继承自 NodeComponent。
比如这个是发积分的 node:
@Component("grantScore")
public class GrantScoreNode extends NodeComponent {
@Override
public void process() {
OrderContext ctx = this.getContextBean(OrderContext.class);
// 获取用户、订单信息,计算积分
int points = calcScore(ctx.getOrderAmount());
userService.addScore(ctx.getUserId(), points);
}
}
你是不是发现了?this.getContextBean(OrderContext.class) 就是流程的上下文,我们可以直接在 node 里取值、传值,不需要方法参数传来传去了。上下文对象可以定制,比如你可以创建 OrderContext 来包含当前订单的所有状态。
而且每个 node 还可以做这些事:
- isAccess():判断这个节点是否需要执行,像是“条件执行”
- isContinueOnError():出错了要不要继续往下跑
- isEnd():是否终止流程
非常灵活,非常轻巧。
条件判断?用 IF 和 SWITCH 优雅解决
liteflow 提供了两个特殊组件:
- NodeIfComponent
- NodeSwitchComponent
它们分别用来处理 if 和 switch 的业务场景。举个例子:
@Component("isVipUser")
public class IsVipUserIfNode extends NodeIfComponent {
@Override
public boolean processIf() throws Exception {
OrderContext ctx = this.getContextBean(OrderContext.class);
return ctx.isVip();
}
}
然后你可以在规则文件中这么写:
THEN(IF(isVipUser, grantVipScore), normalScore);
是不是一下子比嵌套 if-else 清晰多了?流程逻辑直接写在 XML 中,能不能进 grantVipScore 是根据 isVipUser 组件的判断结果来的。再复杂点的也不怕,直接 switch 上:
SWITCH(userType).to(processVip, processNormal, processBlackList);
灵活得像前端的路由系统。
并行处理真的爽,when 关键字安排上
在传统代码里,想要做并行处理得怎么整?线程池、异步回调、结果合并、异常处理,一套流程下来堪称“费脑风暴”。
liteflow 提供了一个关键词:WHEN,一切并行,都靠它。像下面这个配置:
THEN(a, WHEN(b, c, d), e)
表示:先执行 a,然后并行跑 b/c/d,等并行完成后再跑 e。自动并行、自动等待、自动异常捕获,线程池也帮你配好了,不香吗?
默认配置下它使用一个全局异步线程池,你也可以通过配置文件来自定义最大线程数、等待时间、队列大小:
liteflow:
when-max-wait-seconds: 10
when-max-workers: 32
when-queue-limit: 1000
反正你只管写业务逻辑,执行层面的事交给它。
业务规则能热部署,开发调试更丝滑
传统代码改逻辑要干嘛?改代码、重启服务、联调……一通操作下来搞半天。
liteflow 支持热部署,只要你用外部存储的规则文件(比如 Nacos、Apollo、ZooKeeper 等),改完之后立马生效,服务根本不用重启。
流程逻辑变动变得很轻松,像改个前端页面似的。
开发调试时,它还能打印每个节点的执行耗时,失败日志都有,非常方便排查问题。
实战落地:订单完成后的并行通知流程
我在项目里就实打实用了 liteflow 来处理订单完成后的异步任务,像是发积分、消息推送、短信通知、邮件提醒,这些流程本来是用异步事件处理的,整合到 liteflow 之后,结构清晰,新增流程也方便。
<chain name="order_finish_flow">
THEN(initOrder, grantScore, sendMq, WHEN(sendEmail, sendSms))
</chain>
每个 node 的代码都很简单,处理逻辑单一,测试覆盖也容易做,不会互相耦合。最重要的是,测试同事看着规则文件都能理解流程,沟通效率大幅提升。
而且我们还用 isAccess() 控制流程,比如遇到非会员就跳过发积分逻辑,避免执行无意义代码,系统资源更节省。
最后
当然了,liteflow 虽然轻量,但也不是万能的。
如果你业务流程真的是“错综复杂、状态回溯、人工介入、审批回退”,那你还是该上 BPM 工作流系统(比如 Activiti、Flowable、Camunda)。liteflow 更适合逻辑结构稳定、但执行内容经常变动的场景,比如电商订单处理、内容审核流、营销活动流程等等。
如果你现在正被各种 if-else 套娃搞到心态爆炸,不妨试试把流程组件化交给 liteflow 来调度。
你会发现,原来把流程写清楚,还真能让人心情舒畅。