1. 概述
Drools 是一个业务规则管理系统(BRMS)解决方案。它提供了一个规则引擎,用于处理事实(Facts)并根据规则与事实的处理结果生成输出。通过集中化业务逻辑,可以快速、低成本地引入变更。
它还通过提供易于理解的规则编写格式,弥合了业务团队与技术团队之间的鸿沟。
2. Maven 依赖
要开始使用 Drools,首先需要在 pom.xml 中添加几个依赖:
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-ci</artifactId>
<version>9.44.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>9.44.0.Final</version>
</dependency>
两个依赖的最新版本可在 Maven 中央仓库获取:kie-ci 和 drools-decisiontables。
3. Drools 基础概念
以下是 Drools 的核心概念:
- 事实(Facts):表示作为规则输入的数据
- 工作内存(Working Memory):存储事实的容器,用于模式匹配,支持修改、插入和删除操作
- 规则(Rule):关联事实与匹配操作的单个规则,可通过 .drl 文件(Drools 规则语言)或 Excel 电子表格中的决策表(Decision Table)定义
- 知识会话(Knowledge Session):持有触发规则所需的所有资源;所有事实插入会话后,匹配的规则被触发
- 知识库(Knowledge Base):表示 Drools 生态系统中的知识,包含规则资源的定位信息,并创建知识会话
- 模块(Module):包含多个知识库,每个知识库可持有不同会话
4. Java 配置
要在给定数据上触发规则,需要实例化框架提供的类,并传入规则文件位置和事实信息:
4.1 KieServices
KieServices 类提供对所有 Kie 构建和运行时设施的访问。它提供多个工厂、服务和实用方法。首先获取 KieServices 实例:
KieServices kieServices = KieServices.Factory.get();
通过 KieServices 创建 KieFileSystem、KieBuilder 和 KieContainer 的新实例。
4.2 KieFileSystem
设置 KieFileSystem:这是框架提供的内存文件系统。以下代码以编程方式定义 Drools 资源(如规则文件和决策表)的容器:
private KieFileSystem getKieFileSystem() {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
List<String> rules = Arrays.asList("com/baeldung/drools/rules/BackwardChaining.drl", "com/baeldung/drools/rules/SuggestApplicant.drl", "com/baeldung/drools/rules/Product_rules.drl.xls");
for (String rule : rules) {
kieFileSystem.write(ResourceFactory.newClassPathResource(rule));
}
return kieFileSystem;
}
这里从 classpath 读取文件(Maven 项目中通常是 /src/main/resources)。
4.3 KieBuilder
通过 KieBuilder 构建 KieFileSystem 的内容,使用 kb.buildAll() 编译所有规则并检查语法错误:
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
4.4 KieRepository
框架自动将构建生成的 KieModule 添加到 KieRepository:
KieRepository kieRepository = kieServices.getRepository();
4.5 KieContainer
使用 KieModule 的 ReleaseId 创建新的 KieContainer。此处 Kie 分配默认 ReleaseId:
ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId();
KieContainer kieContainer
= kieServices.newKieContainer(krDefaultReleaseId);
4.6 KieSession
从 KieContainer 获取 KieSession。应用程序通过 KieSession 交互,存储并执行运行时数据:
KieSession kieSession = kieContainer.newKieSession();
完整配置如下:
public KieSession getKieSession() {
KieBuilder kb = kieServices.newKieBuilder(getKieFileSystem());
kb.buildAll();
KieRepository kieRepository = kieServices.getRepository();
ReleaseId krDefaultReleaseId = kieRepository.getDefaultReleaseId();
KieContainer kieContainer = kieServices.newKieContainer(krDefaultReleaseId);
return kieContainer.newKieSession();
}
5. 实现规则
完成配置后,我们来看两种创建规则的方式。通过一个示例探索规则实现:根据当前薪资和工作经验年限,为特定角色对申请人进行分类。
5.1 Drools 规则文件 (.drl)
简单说,Drools 规则文件包含所有业务规则。规则包含 When-Then 结构:When 部分列出待检查的条件,Then 部分列出条件满足时执行的操作:
package com.baeldung.drools.rules;
import com.baeldung.drools.model.Applicant;
global com.baeldung.drools.model.SuggestedRole suggestedRole;
dialect "mvel"
rule "Suggest Manager Role"
when
Applicant(experienceInYears > 10)
Applicant(currentSalary > 1000000 && currentSalary <=
2500000)
then
suggestedRole.setRole("Manager");
end
通过在 KieSession 中插入 Applicant 和 SuggestedRole 事实触发规则:
public SuggestedRole suggestARoleForApplicant(
Applicant applicant,SuggestedRole suggestedRole){
KieSession kieSession = kieContainer.newKieSession();
kieSession.insert(applicant);
kieSession.setGlobal("suggestedRole",suggestedRole);
kieSession.fireAllRules();
// ...
}
该规则测试 Applicant 实例的两个条件,根据条件满足情况在 SuggestedRole 对象中设置 Role 字段。
通过执行测试验证:
@Test
public void whenCriteriaMatching_ThenSuggestManagerRole(){
Applicant applicant = new Applicant("David", 37, 1600000.0,11);
SuggestedRole suggestedRole = new SuggestedRole();
applicantService.suggestARoleForApplicant(applicant, suggestedRole);
assertEquals("Manager", suggestedRole.getRole());
}
示例中使用的 Drools 关键字说明:
- package:指定 kmodule.xml 中的包名,规则文件位于此包内
- import:类似 Java 的 import 语句,需指定插入 KnowledgeSession 的类
- global:定义会话级别的全局变量,用于传递输入参数或获取输出参数
- dialect:指定条件或操作部分表达式的语法,默认为 Java。Drools 还支持 mvel(Java 应用的表达式语言),支持字段和方法/getter 访问
- rule:定义包含规则名的规则块
- when:指定规则条件,示例中检查 Applicant 的 experienceInYears 是否大于十年且 currentSalary 在特定范围
- then:当 when 块条件满足时执行操作,示例中将 Applicant 角色设为 Manager
5.2 决策表
决策表提供在预格式化 Excel 电子表格中定义规则的能力。Drools 决策表的优势在于非技术人员也能轻松理解。
当存在相似规则但值不同时特别有用——此时在 Excel 表中添加新行比在 .drl 文件中编写新规则更简单。下面根据产品类型应用标签的示例展示决策表结构:
决策表分为不同部分:
- 顶部是标题部分,指定 RuleSet(规则文件所在包)、Import(需导入的 Java 类)和 Notes(规则用途注释)
- 定义规则的核心部分称为 RuleTable,它将应用于同一领域对象的规则分组
后续行包含列类型 CONDITION 和 ACTION。在这些列中,可访问一行中提到的领域对象属性及其在后续行中的值。
触发规则的机制与 .drl 文件相同。
通过执行测试验证规则应用结果:
@Test
public void whenProductTypeElectronic_ThenLabelBarcode() {
Product product = new Product("Microwave", "Electronic");
product = productService.applyLabelToProduct(product);
assertEquals("BarCode", product.getLabel());
}
6. 总结
本文快速探索了在应用程序中使用 Drools 作为业务规则引擎的方法。我们还看到了多种编写规则的方式:既可使用 Drools 规则语言,也可在电子表格中使用易于理解的语言定义规则。
本文完整代码可在 GitHub 获取。