LiteFlow实战:5分钟构建电商促销规则引擎(Spring Boot热更新方案)
电商大促期间,运营团队经常需要临时调整满减、折扣、秒杀等促销策略的组合方式。传统硬编码方式每次修改都需要重新发布应用,而规则引擎的引入能彻底解决这一痛点。本文将基于LiteFlow 2.10.6演示如何快速搭建支持热更新的促销系统。
1. 环境准备与基础配置
首先创建一个Spring Boot项目(推荐使用Spring Initializr),添加LiteFlow依赖:
<dependency> <groupId>com.yomahub</groupId> <artifactId>liteflow-spring-boot-starter</artifactId> <version>2.10.6</version> </dependency>在application.yml中配置规则文件路径和线程参数:
liteflow: rule-source: rules/*.el.xml monitor: enable-log: true when-max-workers: 32 when-queue-limit: 10000提示:生产环境建议将规则文件存储在Nacos/Apollo等配置中心,本文为演示使用本地文件
2. 核心组件开发
定义价格计算上下文对象,用于传递各组件间的数据:
@Data public class PriceContext { private Long userId; private BigDecimal originalPrice; private List<PriceStepVO> priceSteps = new ArrayList<>(); // 当前使用的优惠券ID private Long couponId; // 是否海外购标记 private boolean oversea; }实现满减计算组件:
@Component("fullCutCmp") public class FullCutComponent extends NodeComponent { @Override public void process() { PriceContext context = getContextBean(PriceContext.class); BigDecimal original = context.getOriginalPrice(); // 满300减50的规则 if (original.compareTo(new BigDecimal(300)) >= 0) { BigDecimal newPrice = original.subtract(new BigDecimal(50)); context.addPriceStep(new PriceStepVO( "FULL_CUT", original, newPrice, "满300减50优惠" )); } } }折扣组件实现示例:
@Component("discountCmp") public class DiscountComponent extends NodeComponent { @Override public boolean isAccess() { // 只有特定用户组享受折扣 return getUserGroup() == VIP_USER; } @Override public void process() { PriceContext context = getContextBean(PriceContext.class); BigDecimal currPrice = context.getLatestPrice(); BigDecimal newPrice = currPrice.multiply(new BigDecimal("0.9")); context.addPriceStep(new PriceStepVO( "VIP_DISCOUNT", currPrice, newPrice, "VIP用户9折" )); } }3. 规则编排与热更新
在resources/rules目录下创建promotion.el.xml:
<flow> <chain name="promotionChain"> <!-- 基础促销流程 --> THEN( fullCutCmp, discountCmp, IF(isRushBuy, rushBuyCmp) ); </chain> </flow>当需要新增优惠券抵扣功能时,只需:
- 开发新的优惠券组件
- 修改规则文件为:
<chain name="promotionChain"> THEN( fullCutCmp, discountCmp, IF(hasCoupon, couponCmp), IF(isRushBuy, rushBuyCmp) ); </chain>无需重启应用,修改立即生效。可通过以下接口测试:
@RestController public class PromotionController { @Autowired private FlowExecutor flowExecutor; @PostMapping("/calculate") public String calculate(@RequestBody OrderDTO order) { LiteflowResponse response = flowExecutor.execute2Resp( "promotionChain", order, PriceContext.class ); return response.getContextBean(PriceContext.class).formatSteps(); } }4. 高级特性与生产建议
4.1 复杂流程编排
LiteFlow支持混合编排模式:
<chain name="complexChain"> THEN( prepareData, WHEN( checkInventory, checkUserCredit ), SWITCH(paymentType).to( creditPayCmp, couponPayCmp, defaultPayCmp ), confirmOrder ); </chain>4.2 生产环境配置建议
| 配置项 | 推荐值 | 说明 |
|---|---|---|
| when-max-workers | CPU核心数*2 | 并行任务线程数 |
| when-queue-limit | 5000-10000 | 任务队列容量 |
| slot-size | 1024的倍数 | 上下文槽位大小 |
| retry-count | 1-3 | 组件失败重试次数 |
4.3 监控与排查
启用监控日志后,可以通过以下方式查看执行情况:
# 查看最近10条执行记录 curl http://localhost:8080/liteflow/getRequestList?count=10 # 获取具体请求详情 curl http://localhost:8080/liteflow/getRequestInfo?requestId=xxx5. 性能优化实践
组件设计原则:
- 保持组件单一职责
- 避免在组件中进行IO密集操作
- 耗时操作使用WHEN并行执行
常见性能瓶颈解决方案:
- 数据库查询瓶颈:
@Component("userCheckCmp") public class UserCheckComponent extends NodeComponent { @Override public void process() { // 错误做法:每次执行都查询数据库 // User user = userDao.getById(userId); // 正确做法:提前加载到上下文 User user = getContextBean(UserContext.class).getUser(); } }- 并行任务超时控制:
liteflow: when-max-wait-seconds: 5 # 并行任务最大等待时间- 上下文优化:
// 轻量级上下文实现 public class LightweightContext extends ContextBean { private Map<String, Object> data = new ConcurrentHashMap<>(); public void put(String key, Object value) { data.put(key, value); } public <T> T get(String key) { return (T) data.get(key); } }在618大促期间,某电商平台通过LiteFlow实现促销策略动态调整,将规则变更发布时间从原来的30分钟(需要灰度发布)缩短到10秒内生效,期间成功应对了23次紧急策略调整。