共计 2400 个字符,预计需要花费 6 分钟才能阅读完成。
背景痛点:为什么我们需要规则引擎
在电商优惠券、金融风控等业务场景中,我们经常遇到这样的困境:

- 业务规则频繁变更(比如每周调整营销策略)
- 多重条件组合导致 if-else 嵌套爆炸(风控规则常超过 10 层判断)
- 业务人员希望自主调整规则权重
传统硬编码方式会产生这些问题:
- 每次修改都需要重新发布应用
- 历史规则难以追溯(Git 记录无法直观体现业务语义)
- 测试用例随着规则增长呈指数级增加
这正是 DDD 中规则模式(Rules Pattern)要解决的问题——将易变的业务规则从核心域逻辑中剥离。
技术选型:规则引擎横向对比
主流 Java 规则引擎能力矩阵:
| 引擎 | 学习成本 | 动态更新 | 性能 | 适用场景 |
|---|---|---|---|---|
| Drools | 高 | 支持 | 优 | 复杂规则链 |
| EasyRules | 低 | 不支持 | 良 | 简单规则集 |
| MVEL | 中 | 支持 | 中 | 脚本式规则 |
选择 Drools 的核心原因:
- spec 驱动 :通过 DRL/YAML 声明式定义规则,业务人员可读
- Rete 算法 :对多条件规则有优化,避免重复计算
- AgendaGroup:支持规则分组执行,实现灰度发布
实现方案:Spring Boot 集成 Drools
基础环境搭建
- 添加 Maven 依赖(注意匹配 Spring Boot 版本):
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.59.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.59.0.Final</version>
</dependency>
- 创建规则定义文件(resources/rules/discount.drl):
rule "VIP 用户折扣"
agenda-group "discount"
when
$user : User(level == "VIP", $total: totalAmount)
$order : Order(amount >= 1000)
then
$order.setDiscount($total * 0.2);
end
核心服务实现
动态加载规则的服务类:
@RefreshScope
@Service
public class RuleService {
private final KieContainer kieContainer;
// 通过 Command 模式执行规则
public void executeRules(Object fact, String agendaGroup) {KieSession session = kieContainer.newKieSession();
try {session.getAgenda().getAgendaGroup(agendaGroup).setFocus();
session.insert(fact);
session.fireAllRules();} finally {session.dispose();
}
}
}
测试用例验证
@Test
void should_apply_vip_discount() {User user = new User("VIP");
Order order = new Order(1500);
ruleService.executeRules(new Object[]{user, order},
"discount"
);
assertEquals(300, order.getDiscount());
}
生产环境最佳实践
规则版本管理
采用 Git+ 数据库混合方案:
- 规则文件保存在 Git 仓库(便于 diff)
- 每次发布生成 MD5 指纹存入 DB
- 通过 /admin/rules 接口查看当前生效版本
性能优化要点
-
KieBase 缓存 :避免重复编译 DRL
KieServices ks = KieServices.Factory.get(); KieFileSystem kfs = ks.newKieFileSystem(); kfs.write("src/main/resources/rules/discount.drl", ks.getResources().newInputStreamResource(drlContent)); KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll(); return ks.newKieContainer(kieBuilder.getKieModule().getReleaseId()); -
Session 复用 :对无状态规则使用 StatelessKieSession
监控方案
通过事件监听器采集指标:
session.addEventListener(new DefaultRuleRuntimeEventListener() {
@Override
public void objectInserted(ObjectInsertedEvent event) {Metrics.counter("rules.fired", "rule", event.getRule().getName()).increment();}
});
进阶思考:规则引擎 + 状态机
在订单状态流转等场景中,可以:
- 用状态机定义主流程(如:待支付→已支付→发货中)
- 用规则引擎处理状态转换条件(如:
- 支付超时自动取消
- 黑名单用户拦截发货)
- 通过 AgendaGroup 实现阶段式规则触发
这种组合方案既能保证主流程清晰,又能灵活处理业务异常分支。
总结
通过 Drools 实现规则与代码解耦后,我们获得了:
- 规则变更实时生效(配合 Nacos 配置中心)
- 业务逻辑可视化(通过决策表)
- 历史版本可追溯(Git+DB 双存储)
建议从简单场景开始实践,逐步将核心业务规则迁移到引擎中管理。当规则超过 20 条时,这种架构的优势会越来越明显。
正文完
