⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 风象南 「风象南」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

前言

作为一名后端开发,你是否遇到过这样的场景:

运营同学说:”双11活动规则临时调整,满300减60改成满200减50,能马上上线吗?”

产品经理说:”风控策略需要微调一下,这个规则能不能今晚就生效?”

老板说:”竞品降价了,我们的VIP折扣也要调整,最好现在就能改!”

每次遇到这种情况,我们都要:修改代码 → 重新打包 → 发布部署 → 重启服务。这个流程短则半小时,长则几个小时,错过最佳时机不说,还要承担发布风险。

今天,我们来聊聊如何用动态规则引擎解决这个痛点!

业务痛点:规则变更的”老大难”问题

传统方式的困境

在传统的业务系统中,业务规则通常硬编码在业务逻辑中:

// 传统的硬编码方式
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测试需要不同的定价策略
  • 竞品价格变动需要快速跟进

金融行业:

  • 风控模型需要根据市场情况实时调整
  • 利率政策变化需要快速响应
  • 审核规则需要根据业务发展动态优化

内容平台:

  • 推荐算法需要不断优化
  • 内容审核规则需要及时更新
  • 用户等级体系需要灵活调整

解决方案:动态规则引擎

核心思路

动态规则引擎的本质是将业务规则与业务代码分离:

  • 业务代码:负责流程控制和数据处理
  • 业务规则:以脚本形式独立存储,运行时动态执行
传统方式:业务逻辑 = 流程控制 + 业务规则(硬编码)
动态规则:业务逻辑 = 流程控制 + 业务规则(脚本化)

技术选型

本演示DEMO我选择了以下技术栈:

  • 规则引擎:QLExpress - 阿里开源
  • 后端框架:Spring Boot - 快速开发
  • 前端技术:HTML5 + TailwindCSS

核心实现:手把手搭建动态规则引擎

1. 项目结构设计

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 # 业务演示页面

2. 规则引擎核心实现

@Slf4j
@Service
public class DynamicRuleEngine {

// 内存存储规则,实际项目可使用数据库
privatefinal Map<String, RuleScript> ruleCache = new ConcurrentHashMap<>();
privatefinal 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());
}
}
}

3. 业务服务集成

@Service
@RequiredArgsConstructor
public class OrderService {

privatefinal 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);

returnnew 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;
}
}

4. REST API接口

@RestController
@RequestMapping("/api/rules")
@RequiredArgsConstructor
public class RuleController {

privatefinal 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;
}

应用场景实战

场景1:电商平台动态定价

需求:根据用户等级和订单金额,动态计算优惠价格

传统方式

// 硬编码,修改需要重新发布
if ("GOLD".equals(userLevel) && amount >= 100) {
return amount * 0.8;
}

动态规则方式

// 规则脚本,可随时修改
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";

业务价值

  • 快速响应:市场风险变化时立即调整
  • 精细化控制:不同场景使用不同策略
  • A/B测试:同时运行多套策略进行对比

场景3:营销活动灵活配置

需求:支持复杂的营销活动规则

规则示例

// 双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;

运营效果

  • 活动预热:提前配置规则,定时生效
  • 实时调整:根据活动效果实时优化
  • 快速止损:发现问题立即回滚规则

总结

通过将业务规则从代码中剥离出来,我们实现了:

  • 业务敏捷:规则变更从小时级提升到分钟级
  • 系统稳定:减少了系统发布频次和风险
  • 团队协作:业务人员可以直接参与规则配置
  • 成本降低:减少了开发、测试、运维的工作量

项目源码地址

https://github.com/yuboon/java-examples/tree/master/springboot-dynamic-rule

文章目录
  1. 1. 前言
  2. 2. 业务痛点:规则变更的”老大难”问题
    1. 2.1. 传统方式的困境
    2. 2.2. 真实的业务场景
  3. 3. 解决方案:动态规则引擎
    1. 3.1. 核心思路
    2. 3.2. 技术选型
  4. 4. 核心实现:手把手搭建动态规则引擎
    1. 4.1. 1. 项目结构设计
    2. 4.2. 2. 规则引擎核心实现
    3. 4.3. 3. 业务服务集成
    4. 4.4. 4. REST API接口
  5. 5. 操作界面
    1. 5.1. 规则管理页面
    2. 5.2. 业务演示页面
  6. 6. 应用场景实战
    1. 6.1. 场景1:电商平台动态定价
    2. 6.2. 场景2:风控策略实时调整
    3. 6.3. 场景3:营销活动灵活配置
  7. 7. 总结
  8. 8. 项目源码地址