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();
注意:上面的代碼需要設置日期格式,否則我們在規則文件中寫的日期格式和默認的日期格式不匹配程序會報錯。