• Drools规则属性


    1. 规则属性

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

    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.1 enabled属性

    enabled属性对应的取值为true和false,默认值为true。

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

    rule "rule_comparison_notMemberOf"
        //指定当前规则不可用,当前规则无论是否匹配成功都不会执行
        enabled false
        when
            ComparisonOperatorEntity(names not memberOf list)
        then
            System.out.println("规则rule_comparison_notMemberOf触发");
    end
    

    1.2 dialect属性

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

    注:mvel是一种基于java语法的表达式语言。

    mvel像正则表达式一样,有直接支持集合、数组和字符串匹配的操作符。

    mvel还提供了用来配置和构造字符串的模板语言。

    mvel表达式内容包括属性表达式,布尔表达式,方法调用,变量赋值,函数定义等。

    1.3 salience属性

    salience属性用于指定规则的执行优先级,取值类型为Integer。数值越大越优先执行。每个规则都有一个默认的执行顺序,如果不设置salience属性,规则体的执行顺序为由上到下。

    可以通过创建规则文件salience.drl来测试salience属性,内容如下:

    package test.salience
    
    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
    

    通过控制台可以看到,由于以上三个规则没有设置salience属性,所以执行的顺序是按照规则文件中规则的顺序由上到下执行的。接下来我们修改一下文件内容:

    package testsalience
    
    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
    

    通过控制台可以看到,规则文件执行的顺序是按照我们设置的salience值由大到小顺序执行的。

    建议在编写规则时使用salience属性明确指定执行优先级。

    1.4 no-loop属性

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

    第一步:编写规则文件/resource/rules/noloop.drl

    package testnoloop
    import com.itheima.drools.entity.Student
    /*
        此规则文件用于测试no-loop属性
    */
    rule "rule_noloop"
        when
            // no-loop true
            $student:Student(age == 25)
        then
            update($student);//注意此处执行update会导致当前规则重新被激活
            System.out.println("规则rule_noloop触发");
    end
    

    第二步:编写单元测试

    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();
    
    Student student = new Student();
    student.setAge(25);
    
    //将数据提供给规则引擎,规则引擎会根据提供的数据进行规则匹配,如果规则匹配成功则执行规则
    kieSession.insert(student);
    
    kieSession.fireAllRules();
    kieSession.dispose();
    

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

    1.5 activation-group属性

    activation-group属性是指激活分组,取值为String类型。具有相同分组名称的规则只能有一个规则被触发。

    第一步:编写规则文件/resources/rules/activationgroup.drl

    package testactivationgroup
    /*
        此规则文件用于测试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
    

    第二步:编写单元测试

    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();
    kieSession.fireAllRules();
    kieSession.dispose();
    

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

    1.6 agenda-group属性

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

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

    package testagendagroup
    /*
        此规则文件用于测试agenda-group属性
    */
    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
        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
    

    第二步:编写单元测试

    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();
    

    通过控制台可以看到,只有获取焦点的分组中的规则才会触发。与activation-group不同的是,activation-group定义的分组中只能够有一个规则可以被触发,而agenda-group分组中的多个规则都可以被触发。

    1.7 auto-focus属性

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

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

    package testagendagroup
    
    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
        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"
        auto-focus true //自动获取焦点
        when
        then
            System.out.println("规则rule_agendagroup_4触发");
    end
    

    第二步:编写单元测试

    KieServices kieServices = KieServices.Factory.get();
    KieContainer kieClasspathContainer = kieServices.getKieClasspathContainer();
    KieSession kieSession = kieClasspathContainer.newKieSession();
    kieSession.fireAllRules();
    kieSession.dispose();
    

    通过控制台可以看到,设置auto-focus属性为true的规则都触发了。

    1.8 timer属性

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

    方式一:timer (int: ?)

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

    方式二:timer(cron: )

    此种方式使用标准的unix cron表达式的使用方式来定义规则执行的时间。

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

    package testtimer
    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
    

    第二步:编写单元测试

    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(10000);
    //结束规则引擎
    kieSession.halt();
    kieSession.dispose();
    

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

    1.9 date-effective属性

    date-effective属性用于指定规则的生效时间,即只有当前系统时间大于等于设置的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。

    第一步:编写规则文件/resources/rules/dateeffective.drl

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

    第二步:编写单元测试

    //设置日期格式
    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();
    

    注意:上面的代码需要设置日期格式,否则我们在规则文件中写的日期格式和默认的日期格式不匹配程序会报错。

    1.10 date-expires属性

    date-expires属性用于指定规则的失效时间,即只有当前系统时间小于设置的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。

    第一步:编写规则文件/resource/rules/dateexpires.drl

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

    第二步:编写单元测试

    //设置日期格式
    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();
    

    注意:上面的代码需要设置日期格式,否则我们在规则文件中写的日期格式和默认的日期格式不匹配程序会报错。

  • 相关阅读:
    基于jQuery的自定义插件:实现整屏分页转换的功能
    蝶恋花
    js中面向对象编程
    移动端web页面列表类上拉加载,查看详情,iframe嵌套第三方页面遇到的问题以及解决办法
    控制使用jquery load()方法载入新页面中的元素
    bootstrap-daterangepicker双日历控件开始日期选择问题
    点击select下拉框获取option的属性值
    bootstrap table表格前台分页,点击tab选项,重新刷新表格
    jquery中使元素显示和隐藏方法之间的区别
    jquery对象和DOM对象的相互转换
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14760248.html
Copyright © 2020-2023  润新知