一. 简介
Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效。
二. 环境搭建
1. 从drools官网下载最新drools
http://www.drools.org/download/download.html
Paste_Image.png2. eclipse的drools插件离线安装
- 从官网下载对应版本的插件压缩包
将下载到的压缩包解压,将features,plugins文件夹,拷贝到eclipse的dropins/drools目录(drools目录需要自己建立),然后重启eclipse
3. 使用maven创建drools项目
- 项目的pom中引入drools的依赖
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-test</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>knowledge-api</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-jsr94</artifactId>
<version>6.4.0.Final</version>
</dependency>
三. 快速入门
- 使用骨架库创建一个简单的java maven项目
- 创建规则文件
Sample.drl
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="rules" packages="rules">
<ksession name="ksession-rules"/>
</kbase>
<kbase name="dtables" packages="dtables">
<ksession name="ksession-dtables"/>
</kbase>
<kbase name="process" packages="process">
<ksession name="ksession-process"/>
</kbase>
</kmodule>
- 定义规则之间的关系
kmodule.xml
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="rules" packages="rules">
<ksession name="ksession-rules"/>
</kbase>
</kmodule>
- 编写测试类
package com.sample;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
public class DroolsTest {
public static final void main(String[] args) {
try {
// load up the knowledge base
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("ksession-rules");
// go !
Message message = new Message();
message.setMessage("Hello World");
message.setStatus(Message.HELLO);
kSession.insert(message);
kSession.fireAllRules();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
四. 项目结构说明
Paste_Image.png五. drools工作流程
六. 规则文件(.drl文件)
规则语法:
package /*包名,必须,且必须在第一行,不必与规则为文件的物理路径一致,若自定义函数或查询属于同一包名,不管物理位置如何,都可以调用*/
import /*需要导入的类名*/
global /*全局变量*/
function /*函数*/
query /*查询*/
rule /*规则,可以有多个*/
规则文件
package com.qc.drools;
import com.qc.model.Student;
global java.util.List.studentList;
function void sysName(){
System.out.println("我是张三");
}
rule "规则名称"
<属性><值>
when
条件 Left Hand Side
then
结果 Right Hand Side
package:对一个规则文件而言,package是必须定义的,必须放在规则文件第一行。特别的是,package的名字是随意的,不必必须对应物理路径,跟java的package的概念不同,这里只是逻辑上的一种区分
import:导入规则文件需要使用到的外部变量,这里的使用方法跟java相同,但是不同于java的是,这里的import导入的不仅仅可以是一个类,也可以是这个类中的某一个可访问的静态方法
比如:
import com.drools.demo.point.PointDomain;
import com.drools.demo.point.PointDomain.getById;
global: 定义global全局变量,通常用于返回数据和提供服务全局变量与fact不一样,引擎不能知道全局变量的改变必须要在插入fact之前,设置global变量
function: 规则中的代码块,封装业务操作,提高代码复用函数以function开头,其它与JAVA方法类似业务代码书写采用的是标准JAVA语法
rule:定义一个规则。rule "ruleName"
一个规则可以包含三个部分
属性部分: 定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等
条件部分: 即LHS,定义当前规则的条件,如 when Message(); 判断当前workingMemory中是否存在Message对象
结果部分: 即RHS,这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用
规则事例:
rule "name"
no-loop true
when
$message:Message(status == 0)
then
System.out.println("fit");
$message.setStatus(1);
update($message);
end
属性: activation-group、agenda-group、auto-focus、date-effective、date-expires、dialect、duration、duration-value、enabled、lock-on-active、no-loop、ruleflow-group、salience
salience: 它的作用是用来设置规则执行的优先级,salience 属性的值是一个数字,数字越大执行优先级越高,同时它的值可以是一个负数。默认情况下,规则的salience 默认值为0,所以如果我们不手动设置规则的salience 属性,那么它的执行顺序是随机的
int型,默认值为0
no-loop: 在DRL的then子句中,如果出现insert、update、modify、retract等方法对实例(Fact)做出修改时,当前规则执行完成后会触发该规则使其再执行一次;将no-loop设置为true则会强制规则在出现上述方法的情况下也只执行一次boolean型,默认值为false
date-effective: 该属性是用来控制规则只有在到达后才会触发,在规则运行时,引擎会自动拿当前操作系统的时候与date-effective 设置的时间值进行比对,只有当系统时间>=date-effective 设置的时间值时,规则才会触发执行,否则执行将不执行。在没有设置该属性的情况下,规则随时可以触发,没有这种限制。 date-effective 的值为一个日期型的字符串,默认情况下,date-effective 可接受的日期格式为“dd-MMM-yyyy”,例如2009 年9 月25 日在设置为date-effective 的值时,如果您的操作系统为英文的,那么应该写成“25-Sep-2009”;如果是英文操作系统“25-九月-2009”
当前规则的生效时间string型,无默认值;值中需包含日期和时间
date-expires: 该属性的作用与date-effective 属性恰恰相反, date-expires 的作用是用来设置规则的有效期,引擎在执行规则的时候,会检查规则有没有date-expires 属性,如果有的话,那么会将这个属性的值与当前系统时间进行比对,如果大于系统时间,那么规则就执行,否则就不执行。该属性的值同样也是一个日期类型,默认格式也是“dd-MMM-yyyy”,具体用法与date-effective 属性相同
当前规则的失效时间string型,无默认值;值中需包含日期和时间
enabled: 它是用来定义一个规则是否可用的。该属性的值是一个布尔值,默认该属性的值为true,表示规则是可用的,如果手工为一个规则添加一个enabled 属性,并且设置其enabled 属性值为false,那么引擎就不会执行该规则
dialect: 该属性用来定义规则当中要使用的语言类型,目前Drools5 版本当中支持两种类型的语言:mvel 和java,默认情况下,如果没有手工设置规则的dialect,那么使用的java 语言
设置规则所使用的语言
string型,默认值根据package值判断,值域为java或mvel
duration: 对于一个规则来说,如果设置了该属性,那么规则将在该属性指定的值之后在另外一个线程里触发。该属性对应的值为一个长整型,单位是毫秒,代码清单2-37 里的规则rule1 添加了duration 属性,它的值为3000,表示该规则将在3000 毫秒之后在另外一个线程里触发
设置DRL文件开始执行之后延迟多长时间开始执行这条规则
long型,无默认值
lock-on-active: 当在规则上使用ruleflow-group 属性或agenda-group 属性的时候,将lock-on-action 属性的值设置为true,可能避免因某些Fact 对象被修改而使已经执行过的规则再次被激活执行。可以看出该属性与no-loop 属性有相似之处,no-loop 属性是为了避免Fact 修改或调用了insert、retract、update 之类而导致规则再次激活执行,这里的lock-on-action 属性也是起这个作用,lock-on-active 是no-loop 的增强版属性,它主要作用在使用ruleflow-group 属性或agenda-group 属性的时候。lock-on-active 属性默认值为false
boolean型,默认值为false
activation-group: 该属性的作用是将若干个规则划分成一个组,用一个字符串来给这个组命名,这样在执行的时候,具有相同activation-group 属性的规则中只要有一个会被执行,其它的规则都将不再执行。也就是说,在一组具有相同activation-group 属性的规则当中,只有一个规则会被执行,其它规则都将不会被执行。当然对于具有相同activation-group 属性的规则当中究竟哪一个会先执行,则可以用类似salience 之类属性来实现
不基于任何条件将规则分组string型,无默认值
agenda-group: 规则的调用与执行是通过StatelessSession 或StatefulSession 来实现的,一般的顺序是创建一个StatelessSession 或StatefulSession,将各种经过编译的规则的package 添加到session当中,接下来将规则当中可能用到的Global 对象和Fact 对象插入到Session 当中,最后调用fireAllRules 方法来触发、执行规则。在没有调用最后一步fireAllRules 方法之前,所有的规则及插入的Fact 对象都存放在一个名叫Agenda 表的对象当中,这个Agenda 表中每一个规则及与其匹配相关业务数据叫做Activation,在调用fireAllRules 方法后,这些Activation 会依次执行,这些位于Agenda 表中的Activation 的执行顺序在没有设置相关用来控制顺序的属性时(比如salience 属性),它的执行顺序是随机的,不确定的。 Agenda Group 是用来在Agenda 的基础之上,对现在的规则进行再次分组,具体的分组方法可以采用为规则添加agenda-group 属性来实现。agenda-group 属性的值也是一个字符串,通过这个字符串,可以将规则分为若干个Agenda Group,默认情况下,引擎在调用这些设置了agenda-group 属性的规则的时候需要显示的指定某个Agenda Group 得到Focus(焦点),这样位于该Agenda Group 当中的规则才会触发执行,否则将不执行
基于Agenda将规则分组;只有当某个Agenda组获取到焦点(focus)时,该组的规则才会被执行string型,默认值为MAIN
auto-focus: 前面我们也提到auto-focus 属性,它的作用是用来在已设置了agenda-group 的规则上设置该规则是否可以自动独取Focus,如果该属性设置为true,那么在引擎执行时,就不需要显示的为某个Agenda Group 设置Focus,否则需要。对于规则的执行的控制,还可以使用Agenda Filter 来实现。在Drools 当中,提供了一个名为org.drools.runtime.rule.AgendaFilter 的Agenda Filter 接口,用户可以实现该接口,通过规则当中的某些属性来控制规则要不要执行。org.drools.runtime.rule.AgendaFilter 接口只有一个方法需要实现,方法体如下: public boolean accept(Activation activation); 在该方法当中提供了一个Activation 参数,通过该参数我们可以得到当前正在执行的规则对象或其它一些属性,该方法要返回一个布尔值,该布尔值就决定了要不要执行当前这个规则,返回true 就执行规则,否则就不执行
与agenda-group配合使用,设置焦点的是否可以自动获取boolean型,默认值为false
ruleflow-group: 基于ruleflow将规则分组string型,无默认值,作用是用来将规则划分为一个个的组,然后在规则流当中通过使用ruleflow-group 属性的值,从而使用对应的规则
Left Hand Side: Conditions / LHS —匹配模式(Patterns)
没有字段约束的Pattern
Person()
有文本字段约束的Pattern
Person( name == “bob” )
字段绑定的Pattern
Person( $name : name == “bob” )
变量名称可以是任何合法的java变量,$是可选的,可用于区分字段和变量
Fact绑定的Pattern
$bob : Person( name == “bob” )
字段绑定的Pattern
变量约束的Pattern
Person( name == $name )
比较操作符: > >= < <= == != contains / not contains / memberOf / not memberOf /matches/ not matches
memberOf: 判断某个Fact属性值是否在某个集合中,与contains不同的是他被比较的对象是一个集合,而contains被比较的对象是单个值或者对象
not memberOf: 与memberOf的作用相反
matches: 正则表达式匹配,与java不同的是,不用考虑'/'的转义问题
not matches: 正好相反
Right Hand Side:
insert: 往当前workingMemory中插入一个新的Fact对象,会触发规则的再次执行,除非使用no-loop限定
update: 更新workingMemory中的Fact对象
modify: 修改,与update语法不同,结果都是更新操作
retract: 删除
网友评论