Drools7.x 学习四-规则属性

前面我们已经知道了规则体的构成如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

本篇就是针对规则体的attributes属性部分进行讲解。Drools中提供的属性如下表(部分属性):

属性名说明
salience指定规则执行优先级
dialect指定规则使用的语言类型,取值为java和mvel
enabled指定规则是否启用
date-effective指定规则生效时间
date-expires指定规则失效时间
activation-group激活分组,具有相同分组名称的规则只能有一个规则触发
agenda-group议程分组,只有获取焦点的组中的规则才有可能触发
timer定时器,指定规则触发的时间
auto-focus自动获取焦点,一般结合agenda-group一起使用
no-loop防止死循环

1.enabled属性

enabled属性对应的取值为true和false,默认值为true。
用于指定当前规则是否启用,如果设置的值为false则当前规则无论是否匹配成功都不会触发。

rule "rule_student_age等于10岁用于删除"
enabled false
salience 10  //权重,保重该规则先执行
    when
        $s:Student(age == 10)
    then
        retract($s);//删除内存中的对象
        System.out.println("规则rule_student_age等于10岁触发用于删除");
end

结果打印
在这里插入图片描述
说明
内存中的对象没有被删除,所以其他的规则被触发了。

2.dialect属性

dialect属性用于指定当前规则使用的语言类型,取值为java和mvel,默认值为mvel。

注:mvel是一种基于java语法的表达式语言。
mvel像正则表达式一样,有直接支持集合、数组和字符串匹配的操作符。
mvel还提供了用来配置和构造字符串的模板语言。
mvel表达式内容包括属性表达式,布尔表达式,方法调用,变量赋值,函数定义等。

3.salience属性

salience属性用于指定规则的执行优先级,取值类型为Integer。数值越大越优先执行。每个规则都有一个默认的执行顺序,如果不设置salience属性,规则体的执行顺序为由上到下。
可以通过创建规则文件/resource/rules/salience.drl来测试salience属性,内容如下:

package rules;
dialect  "mvel"

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

测试代码

    @Test
    public void test5(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        int count = kieSession.fireAllRules();
        System.out.println("条数:"+count);
    }

结果打印
在这里插入图片描述
通过控制台可以看到,由于以上三个规则没有设置salience属性,所以执行的顺序是按照规则文件中规则的顺序由上到下执行的。接下来我们修改一下文件内容:

package rules;
dialect  "mvel"

rule "rule_1"
salience 15
    when
        eval(true)
    then
        System.out.println("规则rule_1触发");
end

rule "rule_2"
salience 20
    when
        eval(true)
    then
        System.out.println("规则rule_2触发");
end

rule "rule_3"
salience 10
    when
        eval(true)
    then
        System.out.println("规则rule_3触发");
end

结果打印
在这里插入图片描述
通过控制台可以看到,规则文件执行的顺序是按照我们设置的salience值由大到小顺序执行的。
建议在编写规则时使用salience属性明确指定执行优先级。

4.no-loop属性

no-loop属性用于防止死循环,当规则通过update之类的函数修改了Fact对象时,可能使当前规则再次被激活从而导致死循环。取值类型为Boolean,默认值为false。测试步骤如下:
第一步:编写规则文件/resource/rules/noloop.drl

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

rule "noloop"
    //no-loop true
    when
        $student:Student(age == 25)
    then
        update($student);//注意此处执行update会导致当前规则重新被激活
        System.out.println("规则rule_noloop触发");
end

第二步:编写单元测试

    @Test
    public void test6(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        Student fact=new Student();
        fact.setAge(25);
        fact.setName("张三");
        System.out.println(fact);
        kieSession.insert(fact);
        int count = kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("noloop"));
        System.out.println("条数:"+count);
        System.out.println(fact);
    }

结果打印
打开注释前
在这里插入图片描述

打开注释后在这里插入图片描述

结果说明
通过控制台可以看到,由于没有设置no-loop属性的值,所以发生了死循环。接下来设置no-loop的值为true再次测试则不会发生死循环。

5.activation-group属性

activation-group属性是指激活分组,取值为String类型。具有相同分组名称的规则只能有一个规则被触发
第一步:编写规则文件/resources/rules/activationgroup.drl

package rules;
dialect  "mvel"
/*
    此规则文件用于测试activation-group属性
*/
rule "rule_activationgroup_1"
    activation-group "mygroup"
    when
    then
        System.out.println("规则rule_activationgroup_1触发");
end
rule "rule_activationgroup_2"
    activation-group "mygroup"
    when
    then
        System.out.println("规则rule_activationgroup_2触发");
end

第二步:编写单元测试

    @Test
    public void test7(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        int count = kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("rule_activationgroup"));
        System.out.println("条数:"+count);
        kieSession.dispose();
    }

结果打印
在这里插入图片描述
通过控制台可以发现,上面的两个规则因为属于同一个分组,所以只有一个触发了。同一个分组中的多个规则如果都能够匹配成功,具体哪一个最终能够被触发可以通过salience属性确定。

6.agenda-group属性

agenda-group属性为议程分组,属于另一种可控的规则执行方式。用户可以通过设置agenda-group来控制规则的执行,只有获取焦点的组中的规则才会被触发。

第一步:创建规则文件/resources/rules/agendagroup.drl

package rules;
dialect  "mvel"

/*
    此规则文件用于测试agenda-group属性
*/
rule "rule_agendagroup_1"
    agenda-group "myagendagroup_aaa"
    when
    then
        System.out.println("规则rule_agendagroup_1触发");
end

rule "rule_agendagroup_2"
    agenda-group "myagendagroup_aaa"
    when
    then
        System.out.println("规则rule_agendagroup_2触发");
end
//========================================================
rule "rule_agendagroup_3"
    agenda-group "myagendagroup_2"
    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 test8() {
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        //设置焦点,对应agenda-group分组中的规则才可能被触发
        kieSession.getAgenda().getAgendaGroup("myagendagroup_2").setFocus();
        int count = kieSession.fireAllRules();
        System.out.println("条数:" + count);
        kieSession.dispose();
    }

结果打印
在这里插入图片描述
通过控制台可以看到,只有获取焦点的分组中的规则才会触发。与activation-group不同的是,activation-group定义的分组中只能够有一个规则可以被触发,而agenda-group分组中的多个规则都可以被触发。
疑问对于指定分组的规则,的确只运行指定分组的规则,但是,对于没有设置指定分组的规则,只要符合过滤条件的也会执行。

7.auto-focus属性

auto-focus属性为自动获取焦点,取值类型为Boolean,默认值为false。一般结合agenda-group属性使用,当一个议程分组未获取焦点时,可以设置auto-focus属性来控制。

第一步:修改/resources/rules/agendagroup.drl文件内容如下

package rules;
dialect  "mvel"

/*
    此规则文件用于测试agenda-group属性
*/
rule "rule_agendagroup_1"
    agenda-group "myagendagroup_1"
    auto-focus true
    when
    then
        System.out.println("规则rule_agendagroup_1触发");
end

rule "rule_agendagroup_2"
    agenda-group "myagendagroup_1"
    when
    then
        System.out.println("规则rule_agendagroup_2触发");
end
//========================================================
rule "rule_agendagroup_3"
    agenda-group "myagendagroup_2"
    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
``
第二步:编写单元测试
```java
    @Test
    public void test9() {
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        //设置焦点,对应agenda-group分组中的规则才可能被触发
        int count = kieSession.fireAllRules();
        System.out.println("条数:" + count);
        kieSession.dispose();
    }

结果打印:
在这里插入图片描述
通过控制台可以看到,设置auto-focus属性为true的规则都触发了。
疑问经验证,发现只要agenda-group内有一个规则的auto-focus属性为true,该组内的所有规则都会执行。

8.timer属性

timer属性可以通过定时器的方式指定规则执行的时间,使用方式有两种:

方式一:timer (int: ?)

此种方式遵循java.util.Timer对象的使用方式,第一个参数表示几秒后执行,第二个参数表示每隔几秒执行一次,第二个参数为可选。

方式二:timer(cron: )

此种方式使用标准的unix cron表达式的使用方式来定义规则执行的时间。
第一步:创建规则文件/resources/rules/timer.drl

package rules;
dialect  "mvel"

import java.text.SimpleDateFormat
import java.util.Date
/*
    此规则文件用于测试timer属性
*/
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 test10() 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(new RuleNameStartsWithAgendaFilter("rule_timer"));
            }
        }).start();
        Thread.sleep(10000);
        //结束规则引擎
        kieSession.halt();
        kieSession.dispose();
    }

注意:单元测试的代码和以前的有所不同,因为我们规则文件中使用到了timer进行定时执行,需要程序能够持续一段时间才能够看到定时器触发的效果。
结果打印
在这里插入图片描述

9.date-effective与date-expires属性

date-effective属性用于指定规则的生效时间,即只有当前系统时间大于等于设置的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。
date-expires属性用于指定规则的失效时间,即只有当前系统时间小于设置的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。
二者也可以单独使用
第一步:编写规则文件/resources/rules/dateeffective.drl

package rules;
dialect  "mvel"

/*
    此规则文件用于测试date-effective属性
*/
rule "rule_dateeffective_1"
date-effective "2020-08-01 10:00"
date-expires "2020-10-01 10:00"
    when
    then
        System.out.println("规则rule_dateeffective_1触发");
end

第二步:编写单元测试

    @Test
    public void test11()  {
        System.setProperty("drools.dateformat","yyyy-MM-dd HH:mm");
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieClasspathContainer.newKieSession();
        int count = kieSession.fireAllRules(new RuleNameEqualsAgendaFilter("rule_dateeffective_1"));
        System.out.println("条数:" + count);
        kieSession.dispose();
    }

结果打印
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值