规则引擎:从大量 if 到业务规则动态化
在营销、风控、审批、定价等系统中,经常会出现大量根据条件执行不同业务逻辑的场景。
例如营销活动:
年龄 < 18 → 赠送 5 积分
年龄 >= 18 → 赠送 10 积分
年龄 < 18 && 等级 = v1 → 赠送 20 积分
年龄 >= 18 && 等级 = v2 → 赠送 1000 积分
最直接的实现方式就是写 if-else:
if (age < 18 && "v1".equals(level)) {
addPoint(20);
} else if (age >= 18 && "v2".equals(level)) {
addPoint(1000);
} else if (age < 18) {
addPoint(5);
} else {
addPoint(10);
}
规则少的时候,这种方式没有任何问题。
真正的问题出现在:业务规则越来越多,并且经常发生变化。
每次修改活动规则,都需要:
修改代码
↓
测试
↓
打包
↓
发布
↓
新规则生效
因此问题并不是 if 本身,而是:
频繁变化的业务规则被硬编码到了程序中。
规则引擎就是为了解决这类问题。
一、什么是规则引擎?
可以用一句话理解:
规则引擎就是把业务判断从代码中抽离出来,将其变成可配置的规则,再由统一的程序负责解析和执行。
传统模式:
业务规则
↓
Java if-else
↓
编译发布
规则引擎模式:
业务规则
↓
JSON / DSL
↓
规则引擎
↓
匹配条件
↓
执行动作
例如原来的代码:
if (age >= 18 && "v2".equals(level)) {
addPoint(1000);
}
可以描述成一条规则:
{
"conditions": [
{
"field": "age",
"operator": ">=",
"value": 18
},
{
"field": "level",
"operator": "==",
"value": "v2"
}
],
"logic": "AND",
"action": {
"type": "ADD_POINT",
"value": 1000
}
}
此时:
age >= 18
level == v2
赠送 1000 积分
已经不再属于 Java 源代码,而变成了业务数据。
以后修改年龄、会员等级、积分数量,只需要修改规则,而不需要修改业务代码。
二、规则引擎解决的不是“消灭 if”
规则引擎并不是让系统从此没有 if。
因为:
age >= 18
无论怎么设计,底层最终都需要进行一次判断。
规则引擎真正解决的是:
不再为每一条业务规则编写一套新的 if-else。
程序只实现通用能力:
字段读取
条件比较
AND / OR
规则匹配
动作执行
例如:
boolean evaluate(Condition condition, User user) {
Object actual = getValue(user, condition.getField());
return switch (condition.getOperator()) {
case ">" -> compare(actual, condition.getValue()) > 0;
case "<" -> compare(actual, condition.getValue()) < 0;
case "==" -> Objects.equals(actual, condition.getValue());
default -> false;
};
}
以后增加:
age > 20
orderCount > 5
level == v3
city == 上海
都只是增加规则数据。
规则数量增加,并不意味着 Java 业务代码跟着增加。
三、什么时候适合使用规则引擎?
规则引擎比较适合两个特点同时存在的业务:
判断逻辑复杂 + 规则经常变化。
典型场景包括:
| 业务 | 规则示例 |
|---|---|
| 营销活动 | 不同用户赠送不同积分、优惠券 |
| 风控系统 | 根据金额、设备、地区判断风险 |
| 审批系统 | 不同金额进入不同审批流程 |
| 会员体系 | 根据等级、消费金额计算权益 |
| 定价系统 | 根据用户、地区、时间动态定价 |
| 推荐策略 | 根据用户标签匹配不同策略 |
例如:
如果:
用户年龄 >= 18
AND
会员等级 = v2
AND
最近30天下单次数 >= 5
那么:
赠送 1000 积分
这种业务非常适合规则化。
但如果系统只有:
if (status == SUCCESS) {
sendMessage();
}
而且几年都不会变化,就完全没有必要为了“高级”而引入规则引擎。
四、规则引擎的核心模型
理解规则引擎,只需要先记住三个概念:
Fact + Rule → Action
Fact:事实
事实就是参与规则计算的数据。
例如:
{
"age": 22,
"level": "v2",
"orderCount": 10
}
Rule:规则
age >= 18
AND
level == v2
Action:动作
规则匹配成功以后执行:
赠送积分
发送优惠券
增加标签
进入审批
发送消息
所以完整过程就是:
用户数据 Fact
+
业务规则 Rule
↓
条件匹配
↓
是否命中规则?
↓
YES
↓
执行 Action
这就是规则引擎最核心的工作。
五、实际项目中怎么使用?
实际项目通常不会让运营人员直接写 JSON。
而是提供一个图形化页面:
条件一:
[年龄] [大于等于] [18]
AND
条件二:
[会员等级] [等于] [v2]
↓
执行动作:
[赠送积分] [1000]
前端将配置转换成 JSON:
{
"logic": "AND",
"conditions": [
{
"field": "age",
"operator": ">=",
"value": 18
},
{
"field": "level",
"operator": "==",
"value": "v2"
}
],
"action": {
"type": "ADD_POINT",
"value": 1000
}
}
保存到数据库。
运行时:
运营配置规则
↓
图形化页面
↓
JSON
↓
数据库存储
↓
规则加载
↓
┌─────────────┐
│ 规则引擎 │
└─────────────┘
↓
条件匹配
↓
Action 执行
这样修改规则时,只需要更新配置即可。
六、Groovy 和规则引擎是什么关系?
这里需要特别区分:
Groovy 不是规则引擎。
规则引擎解决的是:
业务规则如何描述?
业务规则如何匹配?
业务规则如何执行?
Groovy 解决的是:
规则发生变化以后,
如何动态编译并执行新的逻辑?
例如:
JSON
↓
解析规则
↓
生成 Groovy
↓
动态编译
↓
执行
假设 JSON 描述:
age >= 18 AND level == v2
可以动态生成:
user.age >= 18 && user.level == "v2"
通过 Groovy 动态编译加载。
这样:
修改规则
↓
生成新代码
↓
动态编译
↓
替换旧规则
↓
立即生效
就不需要因为修改营销规则而重新发布整个 Java 服务。
因此可以简单理解为:
JSON / DSL
↓
解决规则描述问题
规则引擎
↓
解决规则匹配和执行问题
Groovy
↓
解决动态编译和热更新问题
七、总结
规则引擎最核心的思想,其实不是某个框架或者某门语言,而是:
将频繁变化的业务规则与稳定的程序代码分离。
传统模式:
需求变化
↓
修改 if-else
↓
重新发布
规则引擎模式:
需求变化
↓
修改规则配置
↓
动态加载
↓
立即生效
因此,当一个系统出现:
大量条件判断
+
规则频繁变化
+
业务人员希望配置规则
+
不希望每次修改都重新发布
就可以考虑引入规则引擎。
最后用一句话记住它:
规则引擎不是消灭 if,而是把“业务 if”从代码变成数据,让程序从编写规则变成执行规则。