4、规则引擎集成:Drools 规则引擎入门、决策表与决策树、规则与流程的联动
规则引擎这东西,说白了就是把业务决策从代码里抽出来,放到一个可维护、可热更新的地方。我见过太多项目,业务逻辑散落在 if-else 的海洋里,改一个促销规则要发版本、要重启,运维同学都快哭了。
Drools 是 Java 生态里最成熟的规则引擎之一。它基于 Rete 算法,能高效地匹配大量规则。今天我们就把它拆开看看,怎么用、怎么跟流程联动。
4.1 Drools 规则引擎入门
先看一个最简单的例子。假设我们要给电商订单计算折扣:
- 订单金额满 100 元,打 9 折
- 订单金额满 200 元,打 8 折
- 会员额外再打 9.5 折
如果用 Java 写,大概是一堆 if-else。用 Drools 呢?
// Order.java
public class Order {
private double amount;
private boolean isMember;
private double discount;
// getters/setters...
}
// discount.drl
package com.example.rules
import com.example.Order
rule "满100打9折"
when
$o: Order(amount >= 100 && amount < 200)
then
$o.setDiscount(0.9);
System.out.println("应用规则:满100打9折");
end
rule "满200打8折"
when
$o: Order(amount >= 200)
then
$o.setDiscount(0.8);
System.out.println("应用规则:满200打8折");
end
rule "会员额外折扣"
when
$o: Order(isMember == true)
then
$o.setDiscount($o.getDiscount() * 0.95);
System.out.println("应用规则:会员额外折扣");
end
调用起来也很简单:
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession();
Order order = new Order(250.0, true);
kSession.insert(order);
kSession.fireAllRules();
kSession.dispose();
System.out.println("最终折扣:" + order.getDiscount());
// 输出:0.8 * 0.95 = 0.76
我个人习惯把 .drl 文件放在 resources/rules/ 目录下,按业务模块分文件夹。这样项目大了也好找。
4.2 决策表与决策树
当规则数量超过 20 条,或者规则之间有复杂的优先级关系时,纯文本的 .drl 文件就不太好维护了。这时候,决策表和决策树就派上用场了。
4.2.1 决策表(Decision Table)
决策表本质上是把规则以表格形式呈现。Drools 支持 Excel 格式的决策表,业务人员可以直接编辑。
举个例子,运费计算规则:
| 条件:订单金额 | 条件:会员等级 | 条件:配送区域 | 动作:运费 |
|---|---|---|---|
| < 50 | 普通 | 同城 | 10 |
| < 50 | 普通 | 跨省 | 20 |
| < 50 | VIP | 同城 | 5 |
| < 50 | VIP | 跨省 | 10 |
| >= 50 | * | * | 0 |
这张表翻译成 Drools 规则,就是 5 条 rule。但业务人员看表格比看代码直观多了。我曾经在一个物流项目中,把 80 多条运费规则全部用决策表管理,业务方自己就能维护,再也不用排队等开发改代码了。
4.2.2 决策树(Decision Tree)
决策树是另一种可视化规则的方式。它把条件判断组织成树形结构,每个分支代表一个决策路径。
Drools 本身不直接提供决策树编辑器,但我们可以用决策表模拟决策树的效果。或者,用第三方工具(如 SPL、DMN 编辑器)生成决策树模型,再导入 Drools。
我个人更推荐用 DMN(Decision Model and Notation)标准。Drools 7.x 开始支持 DMN,可以直接加载 .dmn 文件。DMN 决策树长这样:
<!-- 简化的 DMN 决策树片段 -->
<decision id="shippingCost" name="运费计算">
<variable name="shippingCost" typeRef="number"/>
<informationRequirement>
<requiredInput href="#orderAmount"/>
<requiredInput href="#memberLevel"/>
<requiredInput href="#region"/>
</informationRequirement>
<decisionTable>
<rule id="r1">
<inputEntry><text>< 50</text></inputEntry>
<inputEntry><text>"普通"</text></inputEntry>
<inputEntry><text>"同城"</text></inputEntry>
<outputEntry><text>10</text></outputEntry>
</rule>
<!-- 更多规则... -->
</decisionTable>
</decision>
决策树的优势在于「可解释性」。你可以沿着树的分支,一步步解释为什么得出这个结论。这在金融风控、医疗诊断等场景下特别重要。
4.3 规则与流程的联动
光有规则还不够,规则需要嵌入到业务流程中。比如:
- 订单提交后,先执行风控规则
- 风控通过后,再执行定价规则
- 定价完成后,执行库存扣减规则
这就是规则与流程的联动。Drools 提供了两种方式:
4.3.1 在流程中调用规则
Drools 的 BPMN 引擎(jBPM)支持在流程节点中嵌入规则任务。你可以在流程设计器里拖一个「规则任务」节点,指定要执行的规则文件或规则流。
<!-- BPMN 流程片段 -->
<bpmn2:process id="orderProcess" name="订单处理流程">
<bpmn2:startEvent id="start"/>
<bpmn2:businessRuleTask id="riskCheck" name="风控检查"
drools:ruleFlowGroup="risk-rules"/>
<bpmn2:businessRuleTask id="pricing" name="定价计算"
drools:ruleFlowGroup="pricing-rules"/>
<bpmn2:endEvent id="end"/>
<bpmn2:sequenceFlow sourceRef="start" targetRef="riskCheck"/>
<bpmn2:sequenceFlow sourceRef="riskCheck" targetRef="pricing"/>
<bpmn2:sequenceFlow sourceRef="pricing" targetRef="end"/>
</bpmn2:process>
对应的 .drl 文件里,用 ruleflow-group 来分组:
rule "风控-黑名单检查"
ruleflow-group "risk-rules"
when
$o: Order(blacklisted == true)
then
$o.setRiskResult("REJECT");
System.out.println("风控不通过:黑名单用户");
end
rule "定价-满减规则"
ruleflow-group "pricing-rules"
when
$o: Order(amount >= 200)
then
$o.setDiscount(0.8);
System.out.println("应用满200减规则");
end
这样,流程引擎会按顺序执行 risk-rules 和 pricing-rules 两个规则组。互不干扰,顺序可控。
4.3.2 在规则中触发流程
反过来,规则也可以触发流程。比如:风控规则判定订单为高风险,自动发起一个「人工审核」流程。
rule "高风险订单-触发人工审核"
when
$o: Order(riskScore > 80)
then
// 启动一个 BPMN 流程实例
ProcessInstance process = kcontext.getKieRuntime()
.startProcess("manualReviewProcess",
Collections.singletonMap("order", $o));
System.out.println("触发人工审核流程,订单ID:" + $o.getId());
end
这种双向联动,让规则和流程不再是孤岛。我做过一个供应链项目,采购订单的审批流程里嵌入了 30 多条规则,包括价格校验、供应商评级、库存预警等。规则引擎负责「判断」,流程引擎负责「流转」,各司其职。
规则负责:「是什么」「该不该」—— 条件判断、决策输出
流程负责:「怎么做」「谁来做」—— 任务分配、状态流转、超时处理
如果某个逻辑既涉及判断又涉及流转,那就拆成「规则+流程节点」的组合。
4.4 本章小结
我们聊了 Drools 的基本用法、决策表和决策树的应用场景,以及规则与流程的联动方式。嗯,这里要注意:规则引擎不是万能的,它最适合「多条件组合判断」和「频繁变化的业务规则」。如果你的规则只有三五条,或者变化频率极低,用 if-else 反而更简单。
最后,送大家一张我整理的规则引擎集成架构图,方便理解整体脉络:
这张图展示了从业务系统到流程引擎,再到规则引擎的调用链路。规则引擎内部又根据规则复杂度,选择 DRL 文件、决策表或 DMN 模型来执行。结果返回流程引擎,驱动下一步操作。