规则引擎
规则引擎的主要思想是:
- 将应用程序中的业务决策部分抽离出来,并使用预定义的语义模块编写业务决策,由用户或开发者在需要时进行配置管理
规则引擎产品有
Drools、VisualRules、iLog
等例如,在信用卡申请业务中,需要根据学历、收入、是否有房、是否有车判断是否符合信用卡申请要求
- 传统的做法是使用
if...else
的做法,代码量大,且不易修改规则引擎实现将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策
- 规则引擎就是一个输入到输出的平台
Drools介绍
Drools
是由JBoss
组织提供的基于Java
语言开发的开源规则引擎,可以将复杂多变的业务规则从硬编码中解放出来以规则脚本的形式存放在文件或者指定的存储介质中(例如存放在数据库中)
使得业务规则的变更不需要修改项目代码、重启服务器就可以在线上环境立即生效
IDEA
中集成了Drools
的插件
Drools
分为两个部分:编译和运行时编译:
- 将规则描述文件按
ANTLR3
语法进行解析,对语法进行正确性的检查- 产生一种中间结构
descr
,descr
用AST
来描述规则
Drools
支持四种规则描述文件,分别是:drl
文件、xls
文件、brl
文件和dsl
文件
- 常用的描述文件是
drl
文件和xls
文件xls
文件更易于维护,更直观,更为被业务人员所理解运行时:
- 将
AST
传到PackageBuilder
,由PackagBuilder
来产生RuleBase
,它包含了一个或多个Package
对象
案例
规则引擎构成
working Memory(工作内存)
Rule Base(规则库)
Inference Engine(推理引擎):
- Pattern Matcher(匹配器)、Agenda(议程)、Execution Engine(执行引擎)
规则引擎执行过程
将初始数据(fact)输入至工作内存(working Memory)
使用匹配器(Pattern Matcher)将规则库中的规则(rule)和数据(fact)匹配,匹配成功的放入到议程(Agenda)中
如果执行规则存在冲突,即同时激活了多个规则:
- 将冲突的规则放入冲突集合(冲突是同时匹配了多条规则,不需要自己处理,drools会自动处理)
解决冲突,将激活的规则按顺序放入议程(Agenda)
执行议程(Agenda)中的规则,重复2-4,直到执行完毕议程中的所有规则
规则文件构成
通常规则文件的后缀为
.drl
drl
是Drools Rule Language
的缩写,规则文件中编写具体的规则内容一套完整的规则文件内容构成如下:
关键字 描述 package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用 import 用于导入类或者静态方法 global 全局变量 function 自定义函数 query 查询 rule end 规则体
Drools
支持的规则文件,除了drl
形式,还有Excel
文件类型的
规则体语法结构
规则体是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分
规则体语法结构如下:
rule "ruleName" //rule关键字,表示规则开始,参数为规则的唯一名称 attributes //规则属性,是rule与when之间的参数,为可选项 when //关键字,后面是规则的条件部分 LHS //Left Hand Side,是规则的条件部分 then //后面跟规则的结果部分 RHS //是规则的结果或行为 end //表示一个规则的结束
rule:关键字,表示规则开始,参数为规则的唯一名称
attributes:规则属性,是rule与when之间的参数,为可选项
when:关键字,后面跟规则的条件部分
LHS(Left Hand Side):是规则的条件部分的通用名称
- 它由零个或多个条件元素组成,如果LHS为空,则它将被视为始终为true的条件元素
then:关键字,后面跟规则的结果部分
RHS(Right Hand Side):是规则的后果或行动部分的通用名称
end:关键字,表示一个规则结束
基础语法
contains:检查一个Fact对象的某个属性值是否包含一个指定的对象值
not contains:检查一个Fact对象的某个属性值是否不包含一个指定的对象值
memberOf:判断一个Fact对象的某个属性是否在一个或多个集合中
not memberOf:判断一个Fact对象的某个属性是否不在一个或多个集合中
matches:判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配
not matcher:判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配
注释
在
drl
形式的规则文件中使用注释和Java
类中使用注释一致,分为单行注释和多行注释单行注释用
//
进行标记,多行注释以/*
开始,以*/
结束
//规则rule1的注释,这是一个单行注释
rule "rule1"
when
then
System.out.println("rule1触发");
end
/*
规则rule2的注释,
这是一个多行注释
*/
rule "rule2"
when
then
System.out.println("rule2触发");
end
内置方法
规则文件的RHS部分的主要作用是通过插入、删除或修改工作内存中的Fact数据,来达到控制规则引擎执行的目的
Drools提供了一些方法可以用来操作工作内存中的数据,操作完成后规则引擎会重新进行相关规则的匹配
- 原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了
update方法:
update方法的作用是更新工作内存中的数据,并让相关的规则重新匹配:
- 更新数据时,要注意防止陷入死循环
rule "年龄小于十岁"
when
$student:Student(age<10)
then
$student:setAge(15)
update($student) //update方法用于更新Fact对象,会导致相关规则重新匹配
end
insert方法:
insert方法的作用是向工作内存中插入数据,并让相关的规则重新匹配
rule "年龄等于十岁"
when
$student:Student(age==10)
then
Student s = new Student();
s.setAge(5);
insert(s); //insert方法的作用是向工作内存中插入Fact对象,会导致相关规则重新匹配
end
retract方法:
retract方法的作用是删除工作内存中的数据,并让相关的规则重新匹配
rule "年龄等于十岁"
when
$student:Student(age==10)
then
retract($student) //retract方法的作用是删除工作内存中的Fact对象,会导致相关规则重新匹配
end
规则属性
salience:指定规则执行的优先级,用数字表示,数字越大优先级越高,如果不设置,默认从上到下执行
dialect:指定规则使用的语言类型,java或mvel
enabled:指定规则是否启用,取值为ture或false,默认为true
date-effective:指定规则生效的时间
date-expires:指定规则失效的时间
timer:定时器,指定规则触发的时间
activation-group:激活分组,同一个组内只能有一个规则触发
agenda-group:议程分组,只有获取焦点的组中的规则才有可能触发,在java代码中获得焦点
auto-focus:自动获取焦点,一般结合agenda-group使用,取值为ture或false
no-loop:防止死循环,当规则使用update之类的函数修改了Fact对象时,使当前规则再次被激活从而导致死循环
session.getAgenda().getAgendaGroup("agenda_group_name").setFocus;
高级语法
global全局变量:
global
键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能够被访问
- 可以用来为规则文件提供数据或服务,语法结构:
global 对象类型 对象名称
注意事项:
如果对象类型为包装类时,在一个规则中改变了
global
的值
- 那么只针对当前规则有效,对其他规则中的
global
不会有影响如果对象类型为集合类型或者javaBean时,在一个规则中改变了
global
的值,对java代码和所有规则都有效
query查询:
query查询提供了一种查询working memory中符合约束条件的Fact对象的简单方法
- 它仅包含规则文件中的LHS部分,不用指定
when
和then
部分并且以end结束
query 查询的名称(可选参数)
LHS
end
function函数:
function关键字用于在规则文件中定义函数,规则体中可以调用定义的
function
函数使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改
function 返回值类型 函数名(可选参数){
//逻辑代码
}
LHS语法
复合值限制in/not in:
复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字
$s:Student(name in ("张三","李四","王五"))
$s:Student(name not in ("张三","李四","王五"))
条件元素eval:
eval用于规则体的LHS部分,并返回一个Boolean类型的值
eval(1==1)
条件元素not:
not用于判断working memory中是否存在某个Fact对象,如果不存在则返回true,存在返回true
not Student(age<10)
条件元素exists:
exists与not相反,用于判断working memory中是否存在某个Fact对象,如果存在则返回true,不存在返回true
exists Student(age<10)
规则继承
规则之间使用extends关键字进行规则部分的继承,类似于java类之间的继承
rule "rule_1"
when
Student(age>10)
then
System.out.println("rule_1触发");
end
rule "rule_2" extends "rule_1" //继承上面的规则
when
Student(age<20) //此处虽然只有一个条件,但继承上面的条件,所以此处的条件是10<age<20
then
System.out.println("rule_2触发");
end
RHS语法
halt:
halt方法的作用是立即终止后面所有规则的执行
rule "rule_1"
when
Student(age>10)
then
System.out.println("rule_1触发");
drools.halt(); //后面的规则不再执行
end
rule "rule_2"
when
Student(age<20)
then
System.out.println("rule_2触发");
end
getWorkingMemory:
getRule方法的作用是返回工作内存中的对象
rule "rule_getWorkingMemory"
when
Student(age>10)
then
System.out.println(drools.getWorkingMemory());
end
getRule:
getRule方法的作用是返回规则对象
rule "rule_getRule"
when
Student(age>10)
then
System.out.println(drools.getRule());
end