平时做业务开发,尤其是电商订单、审批流、数据处理这类场景,是不是经常被层层嵌套的if-else、牵一发而动全身的硬编码流程搞崩溃?
改一个执行顺序,要翻遍整个方法;加一个分支逻辑,生怕漏判导致bug;多人协作开发,流程逻辑散落在各处,维护成本直线飙升。
后来在项目里接入了轻量国产开源框架 LiteFlow,彻底理顺了这类复杂业务逻辑。它主打零侵入、易上手、动态编排的特性,把整块业务拆成独立可复用的组件,流程规则单独配置管理,调整执行顺序、新增分支逻辑都不用改动原有代码,开发和维护效率直接拉满。

一、前期准备:项目环境与核心依赖
先确认基础环境,保证兼容性:
- JDK版本:17+
- SpringBoot版本:3.2.5
- liteflow:2.15.3 (最新稳定版)
新建SpringBoot3项目,只需要引入Web依赖和核心编排框架Starter。
1.1 引入Maven依赖
打开 pom.xml,添加以下依赖:
<!-- SpringBoot3 Web Starter --> org.springframework.boot spring-boot-starter-web <!-- 轻量流程编排框架 Starter --> com.yomahub liteflow-spring-boot-starter 2.15.3 <!-- 工具包,可选 --> cn.hutool hutool-all 5.8.25 1.2 核心配置文件
在 application.yml 中添加极简配置,指定规则文件位置、开启日志,方便调试:
spring: application: name: springboot3-flow-demo# 流程编排核心配置liteflow: # 规则文件路径,放在resources下 rule-source: flow/order-flow.el.xml # 打印执行日志,排查问题更方便 print-execution-log: true # 上下文槽大小,根据并发量调整 slot-size: 1024 # 支持热加载,修改规则无需重启服务 enable-monitor: true配置完直接启动项目,无报错说明依赖集成成功,接下来进入核心实战环节。
二、核心实战:电商订单流程编排
以最常见的电商创建订单流程为例,拆解业务步骤:
- 参数校验:校验订单参数合法性
- 库存校验:校验商品库存是否充足
- 价格计算:计算商品总价、优惠抵扣
- 订单创建:生成订单数据
- 消息通知:推送订单创建成功消息
传统写法会把所有逻辑塞在一个方法里,我们用组件化+规则编排的方式重构,彻底解耦。
2.1 定义流程上下文(数据载体)
上下文用于在各个组件间传递数据,避免局部变量混乱,所有组件共享一份上下文数据:
import lombok.Data;import java.math.BigDecimal;/** * 订单流程上下文 * 存放整个流程的入参、中间结果、出参 */@Datapublic class OrderContext { // 订单入参 private Long userId; private Long goodsId; private Integer goodsNum; // 中间结果 private Boolean stockEnough; private BigDecimal totalPrice; private BigDecimal discountPrice; // 最终结果 private Long orderId; private String orderStatus;}2.2 拆分业务组件(核心单元)
把每个业务步骤封装成独立组件,继承 NodeComponent,用注解标记组件ID,流程规则通过ID调用。
组件1:订单参数校验
import cn.hutool.core.util.ObjectUtil;import com.liteflow.demo.entity.OrderContext;import com.yomahub.liteflow.annotation.LiteflowComponent;import com.yomahub.liteflow.core.NodeComponent;import com.yomahub.liteflow.exception.FlowSystemException;@LiteflowComponent("orderCheckCmp")public class OrderCheckCmp extends NodeComponent { @Override public void process(){ // 获取上下文 OrderContext context = this.getContextBean(OrderContext.class); // 执行业务校验 if (ObjectUtil.hasNull(context.getUserId(), context.getGoodsId(), context.getGoodsNum())) { throw new FlowSystemException("订单参数不能为空"); } if (context.getGoodsNum() <= 0) { throw new FlowSystemException("商品数量必须大于0"); } System.out.println("订单参数校验通过"); }}组件2:商品库存校验
import com.liteflow.demo.entity.OrderContext;import com.yomahub.liteflow.annotation.LiteflowComponent;import com.yomahub.liteflow.core.NodeComponent;import com.yomahub.liteflow.exception.FlowSystemException;@LiteflowComponent("stockCheckCmp")public class StockCheckCmp extends NodeComponent { @Override public void process() { OrderContext context = this.getContextBean(OrderContext.class); // 模拟库存校验 boolean stockEnough = context.getGoodsNum() <= 100; context.setStockEnough(stockEnough); System.out.println("商品库存校验完成,是否充足:" + stockEnough); if (!stockEnough) { throw new FlowSystemException("库存不足,订单创建失败"); } }}组件3:价格计算(priceCalcCmp)
import com.liteflow.demo.entity.OrderContext;import com.yomahub.liteflow.annotation.LiteflowComponent;import com.yomahub.liteflow.core.NodeComponent;import java.math.BigDecimal;@LiteflowComponent("priceCalcCmp")public class PriceCalcCmp extends NodeComponent { @Override public void process() { OrderContext context = this.getContextBean(OrderContext.class); // 模拟商品单价(实际可从DB/缓存获取) BigDecimal goodsPrice = new BigDecimal("99.9"); // 计算商品总价 BigDecimal totalPrice = goodsPrice.multiply(new BigDecimal(context.getGoodsNum())); // 模拟优惠抵扣(满减/折扣逻辑) BigDecimal discountPrice = totalPrice.multiply(new BigDecimal("0.9")).setScale(2, BigDecimal.ROUND_HALF_UP); // 赋值到上下文 context.setTotalPrice(totalPrice); context.setDiscountPrice(discountPrice); System.out.println("价格计算完成,原价:" + totalPrice + ",优惠后:" + discountPrice); }}组件4:订单创建(orderCreateCmp)
import com.liteflow.demo.entity.OrderContext;import com.yomahub.liteflow.annotation.LiteflowComponent;import com.yomahub.liteflow.core.NodeComponent;import java.util.Random;@LiteflowComponent("orderCreateCmp")public class OrderCreateCmp extends NodeComponent { @Override public void process() { OrderContext context = this.getContextBean(OrderContext.class); // 模拟生成订单ID(实际用雪花算法/数据库自增) long orderId = new Random().nextLong(1000000000L, 9999999999L); // 赋值订单信息 context.setOrderId(orderId); context.setOrderStatus("PENDING_PAY"); // 模拟入库操作 System.out.println("订单创建完成,订单ID:" + orderId + ",状态:待支付"); }}组件5:消息通知(msgNotifyCmp)
import com.liteflow.demo.entity.OrderContext;import com.yomahub.liteflow.annotation.LiteflowComponent;import com.yomahub.liteflow.core.NodeComponent;@LiteflowComponent("msgNotifyCmp")public class MsgNotifyCmp extends NodeComponent { @Override public void process() { OrderContext context = this.getContextBean(OrderContext.class); // 模拟消息推送(MQ/短信/站内信) System.out.println("消息通知成功:用户" + context.getUserId() + ",您的订单" + context.getOrderId() + "已创建,请及时支付"); }}2.3 编写流程规则文件
在 resources/flow 目录下,创建 order-flow.el.xml 规则文件,用EL表达式编排组件执行顺序,想改流程直接改这个文件,无需动Java代码(实际项目中可以通过前端配置动态生成)。
<!--?xml version="1.0" encoding="UTF-8"?--> <!-- 定义订单流程链,name为流程唯一标识 --> <!-- THEN表示串行执行,WHEN表示并行执行 --> THEN( orderCheckCmp, stockCheckCmp, priceCalcCmp, orderCreateCmp, msgNotifyCmp ); 规则语法极简,支持串行、并行、条件分支、循环、嵌套子流程,复杂业务轻松搞定。
三、接口调用:流程执行与结果处理
编写Controller接口,注入流程执行器,触发流程并返回结果,和普通接口开发无差异。
import com.yomahub.liteflow.core.FlowExecutor;import com.yomahub.liteflow.flow.LiteflowResponse;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController@RequestMapping("/order")public class OrderController { // 注入流程执行器 @Resource private FlowExecutor flowExecutor; @PostMapping("/create") public String createOrder(@RequestBody OrderContext context) { // 执行流程,参数:流程ID,参数,上下文对象 LiteflowResponse response = flowExecutor.execute2Resp("createOrderChain","", context); // 判断执行结果 if (response.isSuccess()) { OrderContext result = response.getContextBean(OrderContext.class); return "订单创建成功,订单ID:" + result.getOrderId() + ",状态:" + result.getOrderStatus(); } else { return "订单创建失败,原因:" + response.getMessage(); } }}四、实战测试与常见问题
4.1 接口测试
用Postman调用接口,传入参数:
{ "userId": 1001, "goodsId": 2001, "goodsNum": 2}控制台打印执行日志,接口返回订单创建成功;
若传入商品数量为200(大于库存100),则返回库存不足,流程终止,完全符合预期。
4.2 常见问题
- 组件ID重复:每个组件的@LiteflowComponent(value)必须唯一,否则启动报错
- 上下文获取失败:确保execute2Resp传入的上下文类和getContextBean一致
- 规则文件不生效:检查rule-source路径是否正确,文件名后缀是否为.el.xml
- 事务控制:建议在Service层控制事务,组件内只做业务逻辑处理
五、实战总结
这套轻量编排方案,对比传统硬编码优势太明显:
- 解耦彻底:业务逻辑拆分成独立组件,可复用、易测试
- 灵活可变:流程规则单独配置,动态修改无需重启服务
- 上手极快:无复杂概念,会写Spring组件就能快速落地
- 轻量高效:无额外中间件,性能损耗极低,适配高并发场景
不管是订单流程、审批流、数据清洗、任务调度,只要是多步骤、可编排的业务,都能套用这套方案,彻底告别代码臃肿、维护困难的痛点。