深入浅出 Drools 规则引擎
目录
一、规则引擎简介
规则引擎是一种软件系统组件,设计目的是将业务决策逻辑从应用程序的主流程中解耦出来,使得业务规则可以独立于应用程序代码进行管理和变更。这种机制极大地提高了业务灵活性和可维护性,尤其是在那些业务规则频繁变动或者十分复杂的环境中。
本文将介绍 Drools 的基本概念和简单引用,让你能快速上手使用 Drools 规则引擎。
1.1 应用场景
规则引擎的应用领域十分广泛,比如如下应用场景
- 决策支持系统:在金融、保险、医疗等行业中,Drools 可用于构建复杂的决策流程,比如金融行业的风控反欺诈系统、信贷审批、催收分案、支付路由等有广泛的使用
- 动态配置与策略管理:电信、电子商务等领域中,可以根据用户行为、市场条件等动态调整服务策略或营销活动规则。
- 合规性检查:在银行业、证券业和其他监管严格的行业,Drools 可用来实时验证交易是否符合法规要求。
- 物联网(IoT)智能决策:在处理大量传感器数据时,可以利用 Drools 实现基于规则的数据分析和实时决策响应。
1.2 Drools 规则引擎的特点
- 业务与代码分离:Drools 支持业务专家使用自然语言式的规则描述,将业务逻辑从程序代码中抽离出来,便于业务人员维护和更新规则。
- 声明式编程:通过规则文件定义业务逻辑,而非传统的命令式编程,更加直观且易于理解。
- 复杂事件处理(CEP):能够对连续发生的事件流进行实时分析,触发相应的规则动作。
- 推理能力:支持Rete算法优化规则匹配,对于大规模规则集也能保证高效的推理执行。
- 可扩展性:Drools 不仅是一个规则引擎,还提供了完整的规则生命周期管理,包括规则的创建、存储、测试、部署和监控等功能。
- 集成性:Drools 可以无缝集成到Java应用程序中,并与其他企业级框架和技术良好兼容。
二、规则引擎集成
下面以电商满减为例,演示下如何集成 Drools。
首先是添加依赖
// 这里只添加 Drools 相关依赖,其他依赖请自行添加
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${drools.version}</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
<exclusion>
<artifactId>poi</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-test</artifactId>
<version>${drools.version}</version>
</dependency>
第二步,配置 Drools 配置类
@Configuration
public class DroolsConfig {
// 规则文件路径
private static final String RULE_PATH = "rules/test.drl";
@Bean
public KieContainer kieContainer() {
// 设置日期格式
System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
// 将规则添加到 KieFileSystem 中
kieFileSystem.write(ResourceFactory.newClassPathResource(RULE_PATH));
// 构建 kieBuilder 编译规则
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
kieBuilder.buildAll();
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
throw new IllegalStateException(">>> Error Messages:\n" + results.getMessages());
}
// 获取KieModule
KieModule kieModule = kieBuilder.getKieModule();
// 创建KieContainer,装载模块
return kieServices.newKieContainer(kieModule.getReleaseId());
}
}
第三步,在 resources 下添加规则文件
package com.order.rules
import com.scf.drools.model.Order
// 规则文件中函数定义
function boolean orderIsNull(Order order) {
// 规则中通过 eval 来调用函数
return order == null;
}
// 规则的默认执行顺序是从上向下执行,可以通过 salience 指定执行顺序
// 规则一:消费金额 100-200 优惠10元
rule "order_1"
date-effective "2024-04-02 00:00:00" // 生效时间
date-expires "2024-04-03 23:59:59" // 失效时间
when
$order: Order(originalPrice >= 100 && originalPrice < 200)
then
$order.setRealPrice($order.getOriginalPrice() - 10);
// 执行update后,会重新插入到工作内充中匹配其他规则
// update($order)
end
// 规则二:消费金额 200-300 优惠20元
rule "order_2"
when
$order: Order(originalPrice >= 200 && originalPrice < 300)
then
$order.setRealPrice($order.getOriginalPrice() - 20);
update($order)
end
// 规则三:消费金额 300-400 优惠30元
rule "order_3"
when
$order: Order(originalPrice >= 300 && originalPrice < 400)
then
$order.setRealPrice($order.getOriginalPrice() - 30);
update($order)
end
第四步,根据插入的 fact 运行相应的规则
package com.scf.drools.service;
import com.scf.drools.model.Order;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RuleEngineService {
@Autowired
private KieContainer kieContainer;
public void execute(Order fact) {
KieSession kieSession = kieContainer.newKieSession();
try {
kieSession.insert(fact);
kieSession.fireAllRules();
} finally {
kieSession.dispose();
}
}
}
当方法被调用时,就会自动取匹配规则,并执行相应的代码,如果没有规则引擎,大概率是写一堆的 if else 来判断不同的业务逻辑,当然这个例子不叫简单,如果业务非常复杂,试想你将写出什么样的 if else 代码。
三、核心概念
3.1 规则文件的组成
package ....
import ....
rule "ruleName"
attributes
when
LHS
then
RHS
end
规则文件由以下几部分组成
- package:包名,逻辑单位,同一个包下查询或者函数可以直接调用
- import:用于导入类或静态方法
- global:全局变量
- function:自定义函数
- query:定义一个查询语句,这个查询语句不会像规则那样自动触发,而是供您在应用程序中主动调用,用于检索满足特定条件的事实对象集合
- rule end:规则体,规则体语法中包含的内容如下:
- rule:关键字,标识开始,参数为唯一的规则名称
- attrbutes:规则属性,为可选项,包括 date-effective 等
- LHS:规则条件部分,只有规则条件成立才会进入到 RHS
- RHS:规则的后果或行动部分,条件成立后,在这部分做相应的操作
- end:关键字,标识一个规则的结束
3.2 模式匹配
匹配器可以将 rule base 中所有规则与 working memory 中的 fact 对象进行模式匹配,我们需要在 LHS 不分定义规则并进行模式匹配。LHS 不分由一个或多个条件组成,条件称为 pattern。
pattern 的语法结构为:绑定的变量名:Object(filed约束)。比如 $order : Order(originalPrice >= 100),在 LHS 中比较符有下面这些:
符号 | 说明 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
contains | 检查一个fact对象的某个属性值是否包含一个执行的对象值 |
not contains | 检查一个fact对象的某个属性值是否不包含一个执行的对象值 |
member of | 判断一个fact对象的某个属性是否存在一个或多个集合中 |
not member of | 判断一个fact对象的某个属性是否不在一个或多个集合中 |
matchers | 判断一个fact对象的属性是否与提供的标准的java正则表达式进行匹配 |
not matchers | 判断一个fact对象的属性是否不与提供的标准的java正则表达式进行匹配 |
3.2 规则属性
Drools 规则引擎中的规则可以包含多种属性以控制规则的行为、执行顺序以及与其他规则的关系。以下是一些常用的规则属性及其用途:
属性名 | 说明 |
salience | 指定规则执行顺序,默认顺序是规则书写顺序 |
dialect | 指定规则语言的类型,一种是java一种是mvel |
enable | 规则是否启动 |
date-effective | 指定规则生效时间 |
date-expires | 指定规则失效时间 |
activation-group | 激活分组,具有相同分组名称的规则只能有一个规则触发 |
agenda-group | 议程分组,只有获取焦点的组中的规则才有可能触发,组内规则不互斥 |
timer | 定时器,指定规则触发时间 |
auto-focus | 自动获取焦点,一般结合agenda-group一起使用 |
no-loop | 防止死循环 |
ock-on-active | 控制规则在特定条件下是否能够被多次执行。当规则由于满足条件而激活并进入执行阶段后,如果由于规则执行过程中改变了工作内存(Working Memory)中的事实,导致原本已经激活并正在执行的规则的条件再次满足,那么在lock-on-active为true的情况下,该规则不会再被重新激活和执行。 |
规则还可以通过继承拿到 LHS 部分,语法:rule "rule1" extends "rule2" ,rule1继承了rule2,同时只会继承LHS部分。
通过这节介绍相信你对如何使用 Drools 已经非常清楚了,后面的文章将继续介绍其原理和高阶应用,欢迎关注。
往期经典推荐:
更多推荐
所有评论(0)