前言

曾经接触过一个电信移动通讯项目,每个案件大量的业务逻辑变更,但其实里面的业务改动,其实就是一些业务逻辑变动。

而程序员编写的代码也没有任何技术含量,跟着式样书逐字逐句的翻译就行。大量的if/else判断遍布整个项目,维护难度极大。

而这个drools规则引擎,可以方便的将业务的整体逻辑移出,更加方便程序的可读性。

准备

第一步,随便创建maven项目

第二步,pom的引入

<dependency>
        <groupId>org.drools</groupId>
        <artifactId>drools-compiler</artifactId>
        <version>7.10.0.Final</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

第三步,在src\main\resources\META-INF\  下面创建kmodule.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <!--
        name:指定kbase的名称,可以任意,但是需要唯一
        packages:指定规则文件的目录,需要根据实际情况填写,否则无法加载到规则文件
        default:指定当前kbase是否为默认
    -->
    <kbase name="myKbase1" packages="rules" default="true">
        <!--
            name:指定ksession名称,可以任意,但是需要唯一
            default:指定当前session是否为默认
        -->
        <ksession name="ksession-rule" default="true"/>
    </kbase>
</kmodule>

第四步,在src\main\resources\rules 下面创建 规则文件,规则文件可以以drl为结尾,xml为结尾。

案例一

首先创建bean

package com.hikktn.drools.entity;

/**
 * @ClassName Order
 * @Description 订单
 * @Author lisonglin
 * @Date 2021/3/27 21:46
 * @Version 1.0
 */
public class Order {
	private Double originalPrice;//订单原始价格,即优惠前价格
	private Double realPrice;//订单真实价格,即优惠后价格

	public String toString() {
		return "Order{" + "originalPrice=" + originalPrice + ", realPrice=" + realPrice + '}';
	}

	public Double getOriginalPrice() {
		return originalPrice;
	}

	public void setOriginalPrice(Double originalPrice) {
		this.originalPrice = originalPrice;
	}

	public Double getRealPrice() {
		return realPrice;
	}

	public void setRealPrice(Double realPrice) {
		this.realPrice = realPrice;
	}

}

创建bookDiscount.drl文件,建立相应规则

// 图书优惠策略
package book.discount;
// 引入项目
import com.hikktn.drools.entity.Order;

dialect  "mvel"

// 规则一:所购图书总价在100元以下的没有优惠
rule "book_discount_1"
    when
        $order:Order( originalPrice < 100 ) // 模式匹配
    then
        $order.setRealPrice($order.getOriginalPrice());
        System.out.println("没有优惠");
end
@Test
	public void test2(){
		// 获取规则引擎
		KieServices kieServices = KieServices.Factory.get();
		// 获取连接
		KieContainer kieContainer = kieServices.getKieClasspathContainer();

		// 创建会话1
		KieSession kieSession = kieContainer.newKieSession();
		// 构造订单
		Order order =new Order();
		order.setOriginalPrice(50.0);
		// 添加事件
		kieSession.insert(order);
		kieSession.fireAllRules();
		// 关闭会话
		kieSession.dispose();
	}

结果 

没有优惠

 案例二

两个订单不同的规则,不会触发到其他的规则

         AgendaFilter 增加过滤规则
         RuleNameEqualsAgendaFilter  执行名称全匹配的规则
         RuleNameEndsWithAgendaFilter   执行名称以xxx结尾的规则
         RuleNameMatchesAgendaFilter   可以写自己的正则
         RuleNameStartsWithAgendaFilter  执行名称以xxx开头的规则
         RuleNameSerializationAgendaFilter   规则名称序列化代理筛选器

// 规则四:所购图书总价在300元以上的优惠100元
rule "book_discount_4"
    when
        $order:Order(originalPrice >= 300)
    then
        $order.setRealPrice($order.getOriginalPrice() - 100);
        System.out.println("优惠100元");
end

// 规则二:所购图书总价在100到200元的优惠20元
rule "book_discountA"
    when
        $order:Order( originalPrice < 200 && originalPrice >= 100 ) // 模式匹配
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("订单优惠了20元");
end
@Test
	public void test1(){
		// 获取规则引擎
		KieServices kieServices = KieServices.Factory.get();
		// 获取连接
		KieContainer kieContainer = kieServices.getKieClasspathContainer();

		// 创建会话1
		KieSession kieSession = kieContainer.newKieSession();

		// 创建会话2
		KieSession kieSession2 = kieContainer.newKieSession();

		// 构造订单
		Order order =new Order();
		order.setOriginalPrice(500.0);

		Order order2 =new Order();
		order2.setOriginalPrice(100D);

		// 添加订单,针对订单进行规则交互计算
		kieSession.insert(order);
		kieSession2.insert(order2);

		// 激活规则引擎
		kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("book_discount_"));
		// AgendaFilter 增加过滤规则
		// RuleNameEqualsAgendaFilter  执行名称全匹配的规则
		// RuleNameEndsWithAgendaFilter   执行名称以xxx结尾的规则
		// RuleNameMatchesAgendaFilter   可以写自己的正则
		// RuleNameStartsWithAgendaFilter  执行名称以xxx开头的规则
		// RuleNameSerializationAgendaFilter   规则名称序列化代理筛选器
		kieSession2.fireAllRules(new RuleNameEqualsAgendaFilter("book_discountA"));

		// 关闭会话
		kieSession.dispose();
		kieSession2.dispose();
		System.out.println("订单1的原价格:"+order.getOriginalPrice()+ ",优惠价格:"+order.getRealPrice());
		System.out.println("订单2的原价格:"+order.getOriginalPrice()+ ",优惠价格:"+order2.getRealPrice());
	}

结果

优惠100元
订单优惠了20元
订单1的原价格:500.0,优惠价格:400.0
订单2的原价格:500.0,优惠价格:80.0

 内置方法

符号

说明

>

大于

<

小于

>=

大于等于

<=

小于等于

==

等于

!=

不等于

contains

检查一个Fact对象的某个属性值是否包含一个指定的对象值

not contains

检查一个Fact对象的某个属性值是否不包含一个指定的对象值

memberOf

判断一个Fact对象的某个属性是否在一个或多个集合中

not memberOf

判断一个Fact对象的某个属性是否不在一个或多个集合中

matches

判断一个Fact对象的属性是否与提供的标准的Java正则表达式进行匹配

not matches

判断一个Fact对象的属性是否不与提供的标准的Java正则表达式进行匹配

update方法

更新工作内存中的数据,并让相关的规则重新匹配

insert方法

向工作内存中插入数据,并让相关的规则重新匹配。

retract方法

删除工作内存中的数据,并让相关的规则重新匹配。 

package com.hikktn.drools.entity;

import org.kie.api.definition.type.ClassReactive;

import java.io.Serializable;

/**
 * @ClassName Student
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/3/28 21:47
 * @Version 1.0
 */
@ClassReactive
public class Student implements Serializable {

	private int id;
	private int age;
	private String name;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}
package com.hikktn.drools.entity;

import com.hikktn.drools.entity.Student;
// 使用java模板,内置方法必须用分号结束 mvel没有限制,除此外没有其他语言类型
dialect  "mvel"
// 在drools修改属性,不希望触发内置方法,修改了bean的属性,这时在bean 那里加上@ClassReactive注解,同时drools文件声明属性
// 这里的属性必须和bean属性一致,否则报错
declare Student
    id : int
    age : int
    name : String
end

rule "The student is under 16 years old"
    when
        $s:Student(age <= 16)
    then
        // 如果fact没有申明内容,这里的自定义可以进行修改
        $s.setName("未成年");
        // 修改的年纪,结果出现了变更,但是并没有触发下面一条规则
        $s.setAge($s.getAge()+1);
        // 这样的修改bean并没有效果
        update($s)
        System.out.println("这个学生的年纪小于16岁,他还是"+$s.getName()+",明年他满"+$s.getAge());
end

rule "The student is over 16 years old and younger than 30"
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age > 16 , age <= 30)
    then
        Student student =new Student();
        student.setAge(60);
        // update 不能使用,否则报错
        insert(student);
        $s.setName("青年");
        System.out.println("这个学生的年纪大于16岁且小于30岁,他还是"+$s.getName());
end

rule "The student is under 60 years old"
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age >= 60);
    then
        $s.setName("老年");
        System.out.println("这个学生的年纪大于60岁,他还是"+$s.getName());
end
@Test
	public void test4(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();

		Student student =new Student();
		// 测试前面三个规则
		student.setAge(16);
		student.setName("未知");
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

这个学生的年纪小于16岁,他还是未成年,明年他满17
这个学生的年纪大于16岁且小于30岁,他还是青年
这个学生的年纪大于60岁,他还是老年

规则属性

属性名

说明

salience

指定规则执行优先级

dialect

指定规则使用的语言类型,取值为java和mvel

enabled

指定规则是否启用

date-effective

指定规则生效时间

date-expires

指定规则失效时间

activation-group

激活分组,具有相同分组名称的规则只能有一个规则触发

agenda-group

议程分组,只有获取焦点的组中的规则才有可能触发

timer

定时器,指定规则触发的时间

auto-focus

自动获取焦点,一般结合agenda-group一起使用

no-loop

防止死循环

enabled属性

 指定当前规则是否启用,如果设置的值为false则当前规则无论是否匹配成功都不会触发。

rule "The student is 32 years old"
    // 禁用/启用
    enabled false
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age == 32)
    then
        System.out.println("这个学生今年满32岁了,他还是"+$s.getName());
end
@Test
	public void test4(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();

		Student student =new Student();
		student.setAge(32);
		student.setName("未知");
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

不会输出       “这个学生今年满32岁了,他还是...”

 dialect属性

指定语言类型,分为java和mvel

// 使用java模板,内置方法必须用分号结束 mvel没有限制,除此外没有其他语言类型
dialect  "mvel"

salience属性

优先级,数值越大越优先

rule "The student is 31 years old"
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age == 31);
    then
        $s.setName("满年");
        System.out.println("这个学生的年纪正好30岁,他还是"+$s.getName());
end

rule "The student is 31 years old 2"
    // 优先级
    salience 10
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age == 31)
    then
        // 删除工作内存中的fact对象,并重新分配规则
       retract($s);
        System.out.println("这个学生的年纪大于30岁,他还是"+$s.getName());
end
@Test
	public void test4(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();

		Student student =new Student();
		student.setAge(31);
		student.setName("未知");
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

这个学生的年纪大于30岁,他还是未知

no-loop属性

 循环,和java中的while( 条件 ){  } 一样

rule "The student is 33 years old"
    // 死循环开启,默认关闭
    no-loop false
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student( age >= 33 )
    then
        Thread.sleep(1000);
        $s.setAge($s.getAge()+1);
        System.out.println("随着时间的流逝,每过去一年,他的年龄是"+$s.getAge());
        update($s);
        // System.out.println("这个学生今年满32岁了,他还是"+s.getName());
end

rule "The student is under 60 years old"
    when
        // && 和 , 逗号性能更加优化,作用都是一样
        $s:Student(age >= 60);
    then
        // 退出循环
         $s.setAge(32);
         update($s);
        $s.setName("老年");
        System.out.println("这个学生的年纪大于60岁,他还是"+$s.getName());
end
@Test
	public void test4(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();

		Student student =new Student();
		student.setAge(33);
		student.setName("未知");
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

随着时间的流逝,每过去一年,他的年龄是34
随着时间的流逝,每过去一年,他的年龄是35
随着时间的流逝,每过去一年,他的年龄是36
随着时间的流逝,每过去一年,他的年龄是37
随着时间的流逝,每过去一年,他的年龄是38
随着时间的流逝,每过去一年,他的年龄是39
随着时间的流逝,每过去一年,他的年龄是40
随着时间的流逝,每过去一年,他的年龄是41
随着时间的流逝,每过去一年,他的年龄是42
随着时间的流逝,每过去一年,他的年龄是43
随着时间的流逝,每过去一年,他的年龄是44
随着时间的流逝,每过去一年,他的年龄是45
随着时间的流逝,每过去一年,他的年龄是46
随着时间的流逝,每过去一年,他的年龄是47
随着时间的流逝,每过去一年,他的年龄是48
随着时间的流逝,每过去一年,他的年龄是49
随着时间的流逝,每过去一年,他的年龄是50
随着时间的流逝,每过去一年,他的年龄是51
随着时间的流逝,每过去一年,他的年龄是52
随着时间的流逝,每过去一年,他的年龄是53
随着时间的流逝,每过去一年,他的年龄是54
随着时间的流逝,每过去一年,他的年龄是55
随着时间的流逝,每过去一年,他的年龄是56
随着时间的流逝,每过去一年,他的年龄是57
随着时间的流逝,每过去一年,他的年龄是58
随着时间的流逝,每过去一年,他的年龄是59
随着时间的流逝,每过去一年,他的年龄是60
这个学生的年纪大于60岁,他还是老年

 activation-group属性

激活分组,取值为String类型

rule "The student is under 16 years old"
    // 阻止循环
    lock-on-active true
    when
        $s:Student(age <= 16)
    then
        // 如果fact没有申明内容,这里的自定义可以进行修改
        $s.setName("未成年");
        // 修改的年纪,结果出现了变更,但是并没有触发下面一条规则
        $s.setAge($s.getAge()+1);
        // 这样的修改bean并没有效果
        update($s)
        System.out.println("这个学生的年纪小于16岁,他还是"+$s.getName()+",明年他满"+$s.getAge()+"岁");
end

rule "test-activation-group1"
    activation-group "foo"
    when
        $s:Student()
    then
        System.out.println("test-activation-group1 被触发");
end

rule "test-activation-group2"
    activation-group "foo"
    when
        $s:Student()
    then
        System.out.println("test-activation-group2 被触发");
end
@Test
	public void test4(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		kieSession.getAgenda().getActivationGroup("foo");

		Student student =new Student();
		student.setName("未知");
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

这个学生的年纪小于16岁,他还是未成年,明年他满1岁
test-activation-group1 被触发

加上 优先级后

rule "test-activation-group2"
    // 如果加上优先级,那么会形成先触发
    salience 1
    activation-group "foo"
    when
        $s:Student()
    then
        System.out.println("test-activation-group2 被触发");
end

结果

test-activation-group2 被触发
这个学生的年纪小于16岁,他还是未成年,明年他满1岁
test-activation-group2 被触发
test-activation-group1 被触发

 agenda-group属性和auto-focus属性

 agenda-group:议程分组 ,只有获取到焦点,才能触发规则。

auto-focus :自动获取焦点。

package rules;
dialect  "mvel"

rule "rule_agendagroup_1"
    agenda-group "myagendagroup_1"
    when
    then
        System.out.println("规则rule_agendagroup_1触发");
end

rule "rule_agendagroup_2"
    agenda-group "myagendagroup_1"
    when
        eval(false)
    then
        System.out.println("规则rule_agendagroup_2触发");
end
//========================================================
rule "rule_agendagroup_3"
    agenda-group "myagendagroup_2"
    auto-focus true
    when
    then
        System.out.println("规则rule_agendagroup_3触发");
end

rule "rule_agendagroup_4"
    agenda-group "myagendagroup_2"
    when
    then
        System.out.println("规则rule_agendagroup_4触发");
end
@Test
	public void test5() {
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();

		//设置焦点,对应agenda-group分组中的规则才可能被触发
		kieSession.getAgenda().getAgendaGroup("myagendagroup_1").setFocus();

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

规则rule_agendagroup_3触发
规则rule_agendagroup_4触发
规则rule_agendagroup_1触发

timer属性

定时器的作用。

方式一:timer (int: <initial delay> <repeat interval>?)

第一个参数表示几秒后执行,第二个参数表示每隔几秒执行一次,第二个参数为可选。

方式二:timer(cron: <cron expression>)

package rules;
import java.text.SimpleDateFormat
import java.util.Date
dialect  "mvel"

rule "rule_timer_1"
    timer (5s 2s) //含义:5秒后触发,然后每隔2秒触发一次
    when
    then
        System.out.println("规则rule_timer_1触发,触发时间为:" +
                         new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end

rule "rule_timer_2"
    timer (cron:0/1 * * * * ?) //含义:每隔1秒触发一次
    when
    then
        System.out.println("规则rule_timer_2触发,触发时间为:" +
                         new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
end
@Test
	public void test6() throws InterruptedException {
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		final KieSession kieSession = kieClasspathContainer.newKieSession();

		new Thread(new Runnable() {
			public void run() {
				//启动规则引擎进行规则匹配,直到调用halt方法才结束规则引擎
				kieSession.fireUntilHalt();
			}
		}).start();
		Thread.sleep(5000);
		//结束规则引擎
		kieSession.halt();
		kieSession.dispose();
	}

结果

规则rule_timer_2触发,触发时间为:2021-04-01 00:13:06
规则rule_timer_2触发,触发时间为:2021-04-01 00:13:07
规则rule_timer_2触发,触发时间为:2021-04-01 00:13:08
规则rule_timer_2触发,触发时间为:2021-04-01 00:13:09
规则rule_timer_2触发,触发时间为:2021-04-01 00:13:10

 date-effective属性

生效时间,相当于保质期。默认格式:dd-MMM-yyyy

package rules;
dialect  "mvel"

rule "rule_dateexpires_1"
    // 只要在2022年6月1号之前,该规则都可以生效
    date-expires "01-Jun-2022"
    when
    then
        System.out.println("规则rule_dateexpires_1触发");
end
@Test
	public void test7(){
		//设置日期格式
		// System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

规则rule_dateeffective_1触发

  date-expires属性

失效时间,相当于生产时期。默认格式:dd-MMM-yyyy

package rules;
dialect  "mvel"

rule "rule_dateexpires_1"
    // 只要在2020年6月1日后,该规则都可以使用
    date-expires "01-Jun-2020"
    when
    then
        System.out.println("规则rule_dateexpires_1触发");
end
@Test
	public void test7(){
		//设置日期格式
		// System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

规则date-expires_1触发

 global全局变量

设定全局变量

package rules;
dialect  "mvel"
global java.lang.Integer count //定义一个包装类型的全局变量
global com.hikktn.drools.service.UserService userService //定义一个JavaBean类型的全局变量
global java.util.List gList //定义一个集合类型的全局变量

rule "rule_global_1"
    when
    then
        count += 10; //全局变量计算,只对当前规则有效,其他规则不受影响
        userService.save();//调用全局变量的方法
        gList.add("tom");//向集合类型的全局变量中添加元素,Java代码和所有规则都受影响
        gList.add("jack");
        System.out.println("count=" + count);
        System.out.println("gList.size=" + gList.size());
end

rule "rule_global_2"
    when
    then
        userService.save();
        System.out.println("count=" + count);
        System.out.println("gList.size=" + gList.size());
end
package com.hikktn.drools.service;

/**
 * @ClassName UserService
 * @Description TODO
 * @Author lisonglin
 * @Date 2021/4/1 0:23
 * @Version 1.0
 */
public class UserService {

	public void save(){
		System.out.println("UserService.save()...");
	}

}
@Test
	public void test8(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		//设置全局变量,名称和类型必须和规则文件中定义的全局变量名称对应
		kieSession.setGlobal("userService",new UserService());
		kieSession.setGlobal("count",5);
		List list = new ArrayList();//size为0
		kieSession.setGlobal("gList",list);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

UserService.save()...
count=15
gList.size=2
UserService.save()...
count=5
gList.size=2

 query查询

不用返回结果的查询,返回对象

package rules;
import com.hikktn.drools.entity.Student
dialect  "mvel"

//不带参数的查询
//当前query用于查询Working Memory中age<10的Student对象
query "query_1"
    $student:Student(age < 10)
end

//带有参数的查询
//当前query用于查询Working Memory中age>10同时name需要和传递的参数name相同的Student对象
query "query_2"(String sname)
    $student:Student(age > 20 && name == sname)
end
@Test
	public void test9(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		Student student1 = new Student();
		student1.setName("张三");
		student1.setAge(8);

		Student student2 = new Student();
		student2.setName("李四");
		student2.setAge(22);

		//将对象插入Working Memory中
		kieSession.insert(student1);
		kieSession.insert(student2);

		//调用规则文件中的查询
		QueryResults results1 = kieSession.getQueryResults("query_1");
		int size = results1.size();
		System.out.println("size=" + size);
		for (QueryResultsRow row : results1) {
			Student student = (Student) row.get("$student");
			System.out.println(student);
		}

		//调用规则文件中的查询
		QueryResults results2 = kieSession.getQueryResults("query_2","李四");
		size = results2.size();
		System.out.println("size=" + size);
		for (QueryResultsRow row : results2) {
			Student student = (Student) row.get("$student");
			System.out.println(student);
		}

		// 不用开启全局规则使用
		// kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

size=1
Student{id=0, age=8, name='张三'}
size=1
Student{id=0, age=22, name='李四'}

function函数

类似于JavaScript的方法,编写一个共同的方法函数,重复使用。

package rules;
import com.hikktn.drools.entity.Student
dialect  "mvel"

//定义一个函数
function String sayHello(String name){
    return "hello " + name;
}

rule "rule_function_1"
    when
        $student:Student(name != null)
    then
        //调用上面定义的函数
        String ret = sayHello($student.getName());
        System.out.println(ret);
end
@Test
	public void test10(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		Student student = new Student();
		student.setName("小明");

		kieSession.insert(student);
		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

hello 小明

 复合值限制in/not in

像SQL里面的in关键字,判断是否存在

package rules;
import com.hikktn.drools.entity.Student
dialect  "mvel"

rule "in_test"
    when
        $s:Student(name in ("张三","李四","王五"))
    then
        System.out.println("学生里面有"+$s.getName());
end

rule "not_in_test"
    when
        $s:Student(name not in ("张三","李四","王五"))
    then
        System.out.println("学生里面没有"+$s.getName());
end
@Test
	public void test10(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		Student student = new Student();
		student.setName("小明");

		kieSession.insert(student);
		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

学生里面没有小明

 条件元素eval

不推荐使用,性能不行

eval(true)
eval(false)
eval(1 == 1)

条件元素exists

继承规则

package rules;
import com.hikktn.drools.entity.Student
dialect  "mvel"

rule "rule_1"
    when
        Student(age > 10)
    then
        System.out.println("规则:rule_1触发");
end

rule "rule_2" extends "rule_1" //继承上面的规则
    when
        /*
        此处的条件虽然只写了一个,但是从上面的规则继承了一个条件,
        所以当前规则存在两个条件,即Student(age < 20)和Student(age > 10)
        */
        Student(age < 20)
    then
        System.out.println("规则:rule_2触发");
end
@Test
	public void test4() {
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.newKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		Student student = new Student();
		student.setAge(15);
		kieSession.insert(student);

		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

规则:rule_1触发
规则:rule_2触发

 halt

终止后面所有的规则。

package rules;
dialect  "mvel"

rule "rule_halt_1"
    when
    then
        System.out.println("规则:rule_halt_1触发");
        drools.halt();//立即终止后面所有规则执行
end

//当前规则并不会触发,因为上面的规则调用了halt方法导致后面所有规则都不会执行
rule "rule_halt_2"
    when
    then
        System.out.println("规则:rule_halt_2触发");
end
@Test
	public void test10(){
		KieServices kieServices = KieServices.Factory.get();
		KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
		KieSession kieSession = kieClasspathContainer.newKieSession();
		kieSession.fireAllRules();
		kieSession.dispose();
	}

结果

规则:rule_halt_1触发