上一期入门篇:点击跳转
文章目录
规则文件构成
在使用Drools时,通常规则文件的后缀为 .drl
(Drools Rule Language)
完整规则文件内容的构成如下:
关键字 | 描述 |
---|---|
package | 包名,只限于逻辑上的管理,同一个包名下的查询或函数可以直接调用 |
import | 用于导入类或静态方法 |
global | 全局变量 |
function | 自定义函数 |
query | 查询 |
rule end | 规则体 |
Drools之城的规则文件,除了drl,还有 Excel 文件类型的。 |
规则语法结构
规则语法结构如下:
rule "ruleName"
attributes
when
LHS
then
RHS
end
rule
:关键字,表示规则开始,参数为规则的唯一名称。attributes
:规则属性,是rule与when之间的参数,可为选项。when
:关键字,后面跟规则的条件部分LHS
(Left Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将视为始终为true的条件元素 【左手边】
then
:关键字,后面跟规则的结果部分。RHS
(Right Hand Side):是规则的后果或行动部分的通用名称。 【右手边】
end
:关键字,表示一个规则的结束。
注释
在 drl
形式的规则文件中,使用注释和Java类中使用注释一致,分为 单行注释 和 多行注释。
示例:
//规则rule1的注释,这是一个单行注释
rule "rule1"
when
then
System.out.println("rule1触发");
end
/*
规则rule2的注释,
这是一个多行注释
*/
rule "rule2"
when
then
System.out.println("rule2触发");
end
Pattern模式匹配
LHS部分由一个或者多个条件组成,条件又称为pattern。
pattern的语法结构为:绑定变量名:Object(Field约束)
其中绑定变量名可以省略,通常变量名以 $
开始。
如果定义了绑定变量名,就可以在规则体的 RHS
部分使用此变量名来操作对应的 Fact
对象。Field
约束部分是需要返回true或false的0个或多个表达式。
例如我们的入门案例中:
//规则二:100元 - 500元 加100分
rule "order_rule_2"
when
$order:Order(amout >= 100 && amout < 500)
then
$order.setScore(100);
System.out.println("成功匹配到规则二:100元 - 500元 加100分");
end
通过上面的例子我们可以知道,匹配的条件为:
- 工作内存中必须存在Order这种类型的Fact对象-----类型约束
- Fact对象的amout属性值必须大于等于100------属性约束
- Fact对象的amout属性值必须小于100------属性约束
以上条件必须同时满足当前规则才有可能被激活。
比较操作符
Drools提供的比较操作符,如下表:
符号 | 说明 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
contains | 检查一个Fact对象的某个属性值是否包含一个指定的对象值 |
not contains | 检查一个Fact对象的某个属性值是否不包含在一个指定对象值 |
memberOf | 判断一个Fact对象的某个属性是否在一个或多个集合中 |
not memberOf | 判断一个Fact对象的某个属性是否不在一个或多个集合中 |
matches | 判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配 |
not matches | 判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配 |
Drools内置方法
Drools提供了一些方法可以用来操作工作内存中的数据,**操作完成后规则引擎会重新进行相关规则的匹配,**原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。
update方法
update方法的作用是更新工作内存中的数据,并让相关的规则重新匹配。 (要避免死循环)
参数:
// Fact对象,事实对象
Order order = new Order();
order.setAmount(30);
规则:
package com.order
import com.zxb.drools.model.Order
// 规则一:100元以下 不加分
rule "order_rule_1"
when
$order:Order(amount < 100)
then
$order.setAmount(150);
update($order) // update方法用于更新Fact对象, 会导致相关规则重新匹配
System.out.println("成功匹配规则1,不加分");
end
// 规则二:100 - 150 加100分
rule "order_rule_2"
when
$order:Order(amount >= 100, amount < 150)
then
$order.setScore(100);
System.out.println("成功匹配规则2,订单加分100分");
end
测试结果:
2025-07-27T21:47:56.644+08:00 INFO 20424 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2025-07-27T21:47:56.742+08:00 INFO 20424 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase
成功匹配到规则二:100 - 500 元 加100分
订单金额: 100.0, 添加积分: 100.0
insert方法
insert方法的作用是向工作内存中插入数据,并让相关的规则重新匹配。
//规则一:100元以下 不加分
rule "order_rule_1"
when
$order:Order(amout < 100)
then
Order order = new Order();
order.setAmout(130);
insert(order); //insert方法的作用是向工作内存中插入Fact对象,会导致相关规则重新匹配
System.out.println("成功匹配到规则一:100元以下 不加分");
end
//规则二:100元 - 500元 加100分
rule "order_rule_2"
when
$order:Order(amout >= 100 && amout < 500)
then
$order.setScore(100);
System.out.println("成功匹配到规则二:100元 - 500元 加100分");
end
效果如下:
2025-07-27T21:59:03.920+08:00 INFO 23920 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2025-07-27T21:59:04.021+08:00 INFO 23920 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase
成功匹配规则1,不加分
成功匹配规则2,订单加分100分
订单金额: 90.0, 添加积分: 0.0
retract方法
retract方法的作用是删除工作内存中的数据,并让相关的规则重新匹配。
//规则一:100元以下 不加分
rule "order_rule_1"
when
$order:Order(amout < 100)
then
retract($order) //retract方法的作用是删除工作内存中的Fact对象,会导致相关规则重新匹配
System.out.println("成功匹配到规则一:100元以下 不加分");
end
效果如下:
2025-07-27T22:00:55.500+08:00 INFO 41324 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : Start creation of KieBase: defaultKieBase
2025-07-27T22:00:55.595+08:00 INFO 41324 --- [drools_demo] [ main] o.d.c.kie.builder.impl.KieContainerImpl : End creation of KieBase: defaultKieBase
成功匹配规则1,不加分
订单金额: 90.0, 添加积分: 0.0
规则属性
Drools中提供的属性如下表(部分属性):
属性名 | 说明 |
---|---|
salience | 指定规则执行优先级 |
dialect | 指定规则使用的语言类型,取值为java和mvel |
enabled | 指定规则是否启用 |
date-effective | 指定规则生效时间 |
date-expires | 指定规则失效时间 |
activation-group | 激活分组,具有相同分组名称的规则只能有一个规则触发 |
agenda-group | 议程分组,只有获取焦点的组中的规则才有可能触发 |
timer | 定时器,指定规则触发的时间 |
auto-focus | 自动获取焦点,一般结合agenda-group一起使用 |
no-loop | 防止死循环 |
salience属性
salience属性用于指定规则的执行优先级,取值类型为Integer。数值越大越优先执行。每个规则都有一个默认的执行顺序,如果不设置salience属性,规则题默认的执行顺序为由上到下。
可以通过创建规则文件 salience.drl
来测试:
package com.order
rule "rule_1"
when
eval(true)
then
System.out.println("规则rule_1触发");
end
rule "rule_2"
when
eval(true)
then
System.out.println("规则rule_2触发");
end
rule "rule_3"
when
eval(true)
then
System.out.println("规则rule_3触发");
end
输出:
规则rule_1触发
规则rule_2触发
规则rule_3触发
修改为使用 salience
的:
package com.order
rule "rule_1"
salience 9
when
eval(true)
then
System.out.println("规则rule_1触发");
end
rule "rule_2"
salience 10
when
eval(true)
then
System.out.println("规则rule_2触发");
end
rule "rule_3"
salience 8
when
eval(true)
then
System.out.println("规则rule_3触发");
end
输出:
规则rule_2触发
规则rule_1触发
规则rule_3触发
no-loop属性
no-loop属性用于防止死循环,当规则通过update之类的函数修改了Fact对象时,可能使当前规则再次被激活从而导致死循环。取值类型为Boolean,默认值为false,测试规则如下:
// 订单积分规则
package com.order
import com.zxb.drools.model.Order
// 规则一:100元以下 不加分
rule "order_rule_1"
no-loop true // 防止陷入死循环
when
$order:Order(amount < 100)
then
$order.setScore(0);
update($order)
System.out.println("成功匹配规则一: 100元以下 不加分");
end
输出结果:
成功匹配规则一: 100元以下 不加分
订单金额: 90.0, 添加积分: 0.0
Drools高级语法
前面章节我们已经知道了一套完整的规则文件内容构成如下:
关键字 | 描述 |
---|---|
package | 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用 |
import | 用于导入类或者静态方法 |
global | 全局变量 |
function | 自定义函数 |
query | 查询 |
rule end | 规则体 |
重点说一下我们项目需要使用的属性
global全局变量
global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问。可以用来为规则文件提供数据或服务。
语法结构为:global 对象类型 对象名称
在使用global定义的全局变量时有两点需要注意:
1、如果对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。
2、如果对象类型为集合类型或JavaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。
订单Order:
package com.atguigu.drools.model;
public class Order {
private double amout;
public double getAmout() {
return amout;
}
public void setAmout(double amout) {
this.amout = amout;
}
}
积分Integral:
package com.atguigu.drools.model;
public class Integral {
private double score;
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
规则文件:
//订单积分规则
package com.order
import com.atguigu.drools.model.Order
global com.atguigu.drools.model.Integral integral;
//规则一:100元以下 不加分
rule "order_rule_1"
no-loop true //防止陷入死循环
when
$order:Order(amout < 100)
then
integral.setScore(10);
update($order)
System.out.println("成功匹配到规则一:100元以下 不加分");
end
测试:
@Test
public void test1(){
//从Kie容器对象中获取会话对象
KieSession session = kieContainer.newKieSession();
//Fact对象,事实对象
Order order = new Order();
order.setAmout(30);
//全局变量
Integral integral = new Integral();
session.setGlobal("integral", integral);
//将Order对象插入到工作内存中
session.insert(order);
//激活规则,由Drools框架自动进行规则匹配,如果规则匹配成功,则执行当前规则
session.fireAllRules();
//关闭会话
session.dispose();
System.out.println("订单金额:" + order.getAmout());
System.out.println("添加积分:" + integral.getScore());
}
欢迎关注我的公众号【zxb的博客】!