作为一名后端开发,你是否遇到过这样的场景:
运营同学说:"双11活动规则临时调整,满300减60改成满200减50,能马上上线吗?"
产品经理说:"风控策略需要微调一下,这个规则能不能今晚就生效?"
老板说:"竞品降价了,我们的VIP折扣也要调整,最好现在就能改!"
每次遇到这种情况,我们都要:修改代码 → 重新打包 → 发布部署 → 重启服务。这个流程短则半小时,长则几个小时,错过最佳时机不说,还要承担发布风险。
今天,我们来聊聊如何用动态规则引擎解决这个痛点!
01
业务痛点:规则变更的"老大难"问题
传统方式的困境
// 硬编码,修改需要重新发布 if ("GOLD".equals(userLevel) && amount >= 100) { return amount * 0.8; }在传统的业务系统中,业务规则通常硬编码在业务逻辑中:
// 传统的硬编码方式 public BigDecimal calculateVipDiscount(String userLevel, BigDecimal price) { if ("GOLD".equals(userLevel)) { return price.multiply(new BigDecimal("0.8")); // 8折 } else if ("SILVER".equals(userLevel)) { return price.multiply(new BigDecimal("0.9")); // 9折 } return price; // 无折扣 }这种方式存在诸多问题:
响应慢:规则变更需要完整的开发流程
风险高:每次发布都可能影响整个系统
成本大:需要开发、测试、运维多方配合
不灵活:无法快速响应市场变化
真实的业务场景
电商行业:
• 每逢大促活动,优惠规则频繁调整
• A/B测试需要不同的定价策略
• 竞品价格变动需要快速跟进
金融行业:
• 风控模型需要根据市场情况实时调整
• 利率政策变化需要快速响应
• 审核规则需要根据业务发展动态优化
内容平台:
• 推荐算法需要不断优化
• 内容审核规则需要及时更新
• 用户等级体系需要灵活调整
02
解决方案:动态规则引擎
核心思路
动态规则引擎的本质是将业务规则与业务代码分离:
业务代码:负责流程控制和数据处理
业务规则:以脚本形式独立存储,运行时动态执行
技术选型
本演示DEMO我选择了以下技术栈:
规则引擎:QLExpress - 阿里开源
后端框架:Spring Boot - 快速开发
前端技术:HTML5 + TailwindCSS
03
核心实现:手把手搭建动态规则引擎
项目结构设计
springboot-dynamic-rule/ ├── entity/ │ ├── RuleScript.java # 规则实体 │ ├── OrderProcessResult.java # 订单处理结果 │ └── RuleExecuteResponse.java # 规则执行响应 ├── service/ │ ├── DynamicRuleEngine.java # 规则引擎核心 │ └── OrderService.java # 业务服务 ├── controller/ │ ├── RuleController.java # 规则管理API │ └── OrderController.java # 业务API └── resources/ └── static/ ├── index.html # 规则管理页面 └── business.html # 业务演示页面规则引擎核心实现
@Slf4j @Service public class DynamicRuleEngine { // 内存存储规则,实际项目可使用数据库 private final Map<String, RuleScript> ruleCache = new ConcurrentHashMap<>(); private final ExpressRunner expressRunner = new ExpressRunner(); @PostConstruct public void init() { initDefaultRules(); } private void initDefaultRules() { // VIP折扣规则 addRule(new RuleScript("vip_discount", "if (userLevel == \"GOLD\") { return price * 0.8; } " + "else if (userLevel == \"SILVER\") { return price * 0.9; } " + "else { return price; }", "VIP用户折扣规则")); // 满减活动规则 addRule(new RuleScript("full_reduction", "if (totalAmount >= 200) { return totalAmount - 50; } " + "else if (totalAmount >= 100) { return totalAmount - 20; } " + "else { return totalAmount; }", "满减活动规则")); } public RuleExecuteResponse executeRule(String ruleName, Map<String, Object> params) { try { RuleScript rule = ruleCache.get(ruleName); if (rule == null || !rule.isEnabled()) { return RuleExecuteResponse.error("规则不存在或已禁用: " + ruleName); } DefaultContext<String, Object> context = new DefaultContext<>(); if (params != null) { params.forEach(context::put); } Object result = expressRunner.execute(rule.getScript(), context, null, true, false); log.info("执行规则: {}, 结果: {}", ruleName, result); return RuleExecuteResponse.success(result); } catch (Exception e) { log.error("执行规则失败: {}", ruleName, e); return RuleExecuteResponse.error("执行失败: " + e.getMessage()); } } }业务服务集成
@Service @RequiredArgsConstructor public class OrderService { private final DynamicRuleEngine ruleEngine; public OrderProcessResult processOrder(Order order) { List<OrderProcessResult.ProcessStep> steps = new ArrayList<>(); BigDecimal currentAmount = order.getOriginalAmount(); // 1. 应用VIP折扣规则 BigDecimal discountedAmount = applyVipDiscount(order, currentAmount, steps); // 2. 应用满减规则 BigDecimal finalAmount = applyFullReduction(order, discountedAmount, steps); // 3. 计算积分奖励 Integer points = calculatePoints(finalAmount, order); return new OrderProcessResult(/* 构建返回结果 */); } private BigDecimal applyVipDiscount(Order order, BigDecimal currentAmount, List<OrderProcessResult.ProcessStep> steps) { Map<String, Object> params = new HashMap<>(); params.put("userLevel", order.getUserLevel()); params.put("price", currentAmount); RuleExecuteResponse response = ruleEngine.executeRule("vip_discount", params); if (response.isSuccess()) { BigDecimal result = new BigDecimal(response.getResult().toString()); BigDecimal reduction = currentAmount.subtract(result); // 记录处理步骤 steps.add(new OrderProcessResult.ProcessStep( "VIP折扣", "根据用户等级 " + order.getUserLevel() + " 应用折扣", currentAmount, result, reduction, "vip_discount" )); return result; } return currentAmount; } }REST API接口
@RestController @RequestMapping("/api/rules") @RequiredArgsConstructor public class RuleController { private final DynamicRuleEngine dynamicRuleEngine; @GetMapping public ResponseEntity<List<RuleScript>> getAllRules() { return ResponseEntity.ok(dynamicRuleEngine.getAllRules()); } @PostMapping public ResponseEntity<String> addRule(@RequestBody RuleScript ruleScript) { try { dynamicRuleEngine.addRule(ruleScript); return ResponseEntity.ok("规则添加成功"); } catch (Exception e) { return ResponseEntity.badRequest().body("添加失败: " + e.getMessage()); } } @PutMapping("/{ruleName}") public ResponseEntity<String> updateRule(@PathVariable String ruleName, @RequestBody RuleScript ruleScript) { try { dynamicRuleEngine.updateRule(ruleName, ruleScript); return ResponseEntity.ok("规则更新成功"); } catch (Exception e) { return ResponseEntity.badRequest().body("更新失败: " + e.getMessage()); } } @PostMapping("/execute/{ruleName}") public ResponseEntity<RuleExecuteResponse> executeRule( @PathVariable String ruleName, @RequestBody Map<String, Object> params) { RuleExecuteResponse response = dynamicRuleEngine.executeRule(ruleName, params); return ResponseEntity.ok(response); } }操作界面
为了方便大家快速直观的体验规则引擎,DEMO提供了一套简洁的操作界面,包含规则配置与业务场景模拟。
规则管理页面
主要功能:
规则列表:展示所有规则及状态
在线编辑:支持规则脚本的在线修改
实时测试:规则修改后立即测试效果
状态控制:一键启用/禁用规则
业务演示页面
订单模拟器:输入订单信息,查看处理结果
详细步骤:清晰展示每个规则的执行过程
处理历史:记录历史处理结果
关键前端代码:
// 动态执行规则 async function executeRule(ruleName, params) { try { const response = await fetch(`/api/rules/execute/${ruleName}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); const result = await response.json(); if (result.success) { displayResult(`执行成功!结果: ${result.result}`); } else { displayResult(`执行失败: ${result.errorMessage}`); } } catch (error) { displayResult(`请求失败: ${error.message}`); } } // 渲染处理步骤 function displayProcessSteps(processSteps) { const stepsHtml = processSteps.map((step, index) => { const beforeAmount = parseFloat(step.beforeAmount); const afterAmount = parseFloat(step.afterAmount); const reduction = parseFloat(step.reduction); return ` <div class="process-step"> <div class="step-number">${index + 1}</div> <div class="step-content"> <h4>${step.stepName}</h4> <p>${step.description}</p> </div> <div class="step-result"> <div class="amount-change">¥${beforeAmount} → ¥${afterAmount}</div> <div class="reduction">节省 ¥${reduction.toFixed(2)}</div> </div> </div> `; }).join(''); document.getElementById('processingSteps').innerHTML = stepsHtml; }04
应用场景实战
场景1:电商平台动态定价
需求:根据用户等级和订单金额,动态计算优惠价格
传统方式
动态规则方式
// 规则脚本,可随时修改 if (userLevel == "GOLD" && totalAmount >= 100) { return totalAmount * 0.8; } else if (userLevel == "SILVER" && totalAmount >= 50) { return totalAmount * 0.9; } else { return totalAmount; }效果对比
响应速度:从小时级降低到分钟级
发布风险:从系统级降低到规则级
操作门槛:从开发人员扩展到业务人员
场景2:风控策略实时调整
需求:根据实时风险情况,动态调整审核策略
规则示例:
// 风控评分规则 score = baseScore; if (userAge < 18) { score = score - 20; } if (creditLevel == "HIGH") { score = score + 30; } if (monthlyIncome > 10000) { score = score + 15; } return score >= 60 ? "PASS" : "REJECT";// 双11活动规则 if (activityType == "DOUBLE11") { if (totalAmount >= 1000) { return totalAmount - 200; } else if (totalAmount >= 500) { return totalAmount - 80; } else if (totalAmount >= 200) { return totalAmount - 30; } } return totalAmount;业务价值
快速响应:市场风险变化时立即调整
精细化控制:不同场景使用不同策略
A/B测试:同时运行多套策略进行对比
场景3:营销活动灵活配置
需求:支持复杂的营销活动规则
规则示例
运营效果
活动预热:提前配置规则,定时生效
实时调整:根据活动效果实时优化
快速止损:发现问题立即回滚规则
05
总结
通过将业务规则从代码中剥离出来,我们实现了:
业务敏捷:规则变更从小时级提升到分钟级
系统稳定:减少了系统发布频次和风险
团队协作:业务人员可以直接参与规则配置
成本降低:减少了开发、测试、运维的工作量