Drools是一款基于Java的開源規(guī)則引擎
實(shí)現(xiàn)了將業(yè)務(wù)決策從應(yīng)用程序中分離出來。
優(yōu)點(diǎn):
1、簡化系統(tǒng)架構(gòu),優(yōu)化應(yīng)用
2、提高系統(tǒng)的可維護(hù)性和維護(hù)成本
3、方便系統(tǒng)的整合
4、減少編寫“硬代碼”業(yè)務(wù)規(guī)則的成本和風(fēng)險(xiǎn)
Drools的基本工作工程
我們需要傳遞進(jìn)去數(shù)據(jù),用于規(guī)則的檢查,調(diào)用外部接口,同時(shí)還可能獲取規(guī)則執(zhí)行完畢之后得到的結(jié)果
Fact對象:
指傳遞給drools腳本的對象,是一個(gè)普通的javabean,原來javaBean對象的引用,可以對該對象進(jìn)行讀寫操作,并調(diào)用該對象的方法
當(dāng)一個(gè)java bean插入到working Memory(內(nèi)存存儲(chǔ))中,規(guī)則使用的是原有對象的引用,規(guī)則通過對fact對象的讀寫,
實(shí)現(xiàn)對應(yīng)用數(shù)據(jù)的讀寫,對其中的屬性,需要提供get和set方法,規(guī)則中可以動(dòng)態(tài)的前往working memory中插入刪除新的fact對象
Drools的基礎(chǔ)語法:
包路徑,引用,規(guī)則體 (其中包路徑和規(guī)則體是必須的)
Drl文件內(nèi)容:
例子:
hello.drl文件如下:
package rules.testwordrule "test001" when //這里如果為空,則表示eval(true) then System.out.println("hello word");end
package:包路徑,該路徑是邏輯路徑(可以隨便寫,但是不能不寫,最好和文件目錄同名,以(.)的方式隔開),規(guī)則文件中永遠(yuǎn)是第一行
rule:規(guī)則體,以rule開頭,以end結(jié)尾,每個(gè)文件可以包含多個(gè)rule ,規(guī)則體分為3個(gè)部分:LHS,RHS,屬性 三大部分
LHS:(Left Hand Side),條件部分,在一個(gè)規(guī)則當(dāng)中“when”和“then”中間的部分就是LHS部分,在LHS當(dāng)中,可以包含0~N個(gè)條件,如果
LHS為空的話,那么引擎會(huì)自動(dòng)添加一個(gè)eval(true)的條件,由于該條件總是返回true,所以LHS為空的規(guī)則總是返回true。
RHS:(Right Hand Side),在一個(gè)規(guī)則中“then”后面的部分就是RHS,只有在LHS的所有條件都滿足的情況下,RHS部分才會(huì)執(zhí)行。
RHS部分是規(guī)則真正做事情的部分,滿足條件觸發(fā)動(dòng)作的操作部分,在RHS可以使用LHS部分當(dāng)中的定義的綁定變量名,設(shè)置的全局變量、
或者是直接編寫的java代碼,可以使用import的類。
不建議有條件判斷。
可以使用快速操作working Memory的宏函數(shù)和對象,比如insert/insertLogical,update/modify和retract就可以實(shí)現(xiàn)對當(dāng)前Working Memory中的Fact對象
進(jìn)行新增,修改,或者刪除,可以使用drool宏對象,Drools還提供了kcontext的宏對象,該對象可以直接訪問當(dāng)前Working Memory的KnowledgeRuntime。
import:導(dǎo)入規(guī)則文件需要使用到的外部變量,可以導(dǎo)入類,也可以是這個(gè)類中的靜態(tài)方法
例如:
import com.dinpay.dpp.rcp.service.util.RuleLogUtil; 導(dǎo)入類
import com.dinpay.dpp.rcp.service.util.RuleLogUtil.getLog;//導(dǎo)入靜態(tài)方法
Drools的API調(diào)用
API可以分為三類:規(guī)則編譯,規(guī)則收集,規(guī)則執(zhí)行
1、Kmodule.xml的編譯
存放在src/main/resources/META-INF/文件夾下
<?xml version="1.0" encoding="UTF-8"?><kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> <kbase name="rules" packages="rules.testword"> <ksession name="session"/> </kbase></kmodule>
1)、可包含多個(gè)kbase,任意但不能重名
2)、有個(gè)packages,就是src/main/resources下面的文件夾名稱,可定義多個(gè)包,用逗號(hào)隔開
3)、ksession都一個(gè)name,任意字符串但不能重名,可以有多個(gè)
4)、在運(yùn)行時(shí)、KieContainer會(huì)根據(jù)*Model對象來創(chuàng)建KieModule,KieBase,KieSession對象,其中KieModule和KieBase只會(huì)創(chuàng)建一次,而KieSession則可能創(chuàng)建多次
2、API說明,引入drools依賴jar包,drools-core,kie-api,drools-compiler
KieSession;
用于與規(guī)則引擎進(jìn)行交互的會(huì)話
分為兩類:
有狀態(tài)KieSession:KieSession會(huì)在多次與規(guī)則引擎進(jìn)行交互中,維護(hù)會(huì)話狀態(tài),type屬性值是stateful,
最后需要清理KieSession維護(hù)的狀態(tài),調(diào)用dispose()方法
無狀態(tài)StatelessKieSession:StatelessKieSession隔離了每次與規(guī)則引擎的交互,不會(huì)維護(hù)會(huì)話狀態(tài),無副作用,type屬性值是stateless
應(yīng)用場景:數(shù)據(jù)校驗(yàn),運(yùn)算,數(shù)據(jù)過濾,消息路由,任何能被描述成函數(shù)或公式的規(guī)則
Drools內(nèi)部功能詳細(xì)介紹
規(guī)則文件
一個(gè)標(biāo)準(zhǔn)的規(guī)則文件的結(jié)構(gòu)代碼:
package package-name(包名,必須的,只限制于邏輯上的管理,若自定義查詢或者函數(shù)屬于同一個(gè)包名,不管物理位置如何,都可以調(diào)用)
imports (需要導(dǎo)入的類名)
globals (全局變量)
functions (函數(shù))
queries (查詢)
rules (規(guī)則,可以多個(gè))
package在規(guī)則文件中是第一行,其他的順序可以是無序的,package對于規(guī)則文件中規(guī)則的管理只限于邏輯上的管理
規(guī)則語言
rule “name”
attributes ---->屬性
when
LHS ---->條件
then
RHS ---->結(jié)果
end
一個(gè)規(guī)則包含三部分:唯有attributes部分可選,其他都是必填信息
定義當(dāng)前規(guī)則執(zhí)行的一些屬性等,比如是否可被重復(fù)執(zhí)行,過期時(shí)間,生效時(shí)間等
LHS:定義當(dāng)前規(guī)則的條件,如 when Message();判斷當(dāng)前workingMemory中是否存在Message對象
RHS:可以寫java代碼,即當(dāng)前規(guī)則條件滿足執(zhí)行的操作,可以直接調(diào)用Fact對象的方法來操作應(yīng)用
LHS:如果LHS部分為空,自動(dòng)添加一個(gè)eval(true)操作
LHS部分是由一個(gè)或多個(gè)條件組成,條件又稱為pattern(匹配模式),多個(gè)pattern之間可以使用 and 或 or來進(jìn)行連接,同時(shí)還可以使用小括號(hào)來確定pattern的優(yōu)先級(jí)
【綁定變量名:】Object(【filed 約束】)
對于一個(gè)pattern來說"綁定變量名"是可選的,如果在當(dāng)前規(guī)則的LHS部分的其他pattern要使用這個(gè)對象,那么可以通過為該對象綁定設(shè)定一個(gè)
綁定變量名來實(shí)現(xiàn)對其的引用,對于綁定變量的命名,通常的做法是為其添加一個(gè) "$"符號(hào)作為前綴,可以和Fact對象區(qū)分開來
綁定變量可以用于對象上,可以用于對象屬性上,"field約束"是指當(dāng)前對象里相關(guān)字段的條件限制
規(guī)則中LHS部分單個(gè)pattern(模式)的情形。
規(guī)則中"$customer"就是綁定到Customer對象的"綁定變量名",該規(guī)則的LHS部分表示,要求Fact對象必須是Customer類型,該條件滿足,那么它的LHS會(huì)返回true
rule "rule1" when $customer:Customer(age>20,gender=="male") Order(customer==$customer,price>1000) then <action>...
end
第一個(gè)pattern有三個(gè)約束
1、對象類型必須是Customer;
2、Customer的age要大于20
3、Customer的gender要是male
第二個(gè)pattern有三個(gè)約束
1、對象類型必須是Order
2、Order對應(yīng)的Customer必須是前面那個(gè)Customer
3、當(dāng)前這個(gè)Order的price要大于1000
這兩個(gè)pattern沒有符號(hào)連接,在Drools當(dāng)中沒有連接符號(hào),默認(rèn)是and,只有兩個(gè)pattern(模式)都滿足才會(huì)返回true,每行可以用";"結(jié)束
約束連接
對象內(nèi)部的多個(gè)約束連接 "&&"(and),"||"(or)和","(and)來實(shí)現(xiàn)
如果記性常量的比較,必須通過eval(條件)或者對象引用比較對象屬性,不能單獨(dú)引用
12個(gè)類型比較操作符 >|<,>=|<=,==|!=,contains|not contains,memberOf|not memberOf,matches|not matches
Drools屬性說明
salience優(yōu)先級(jí)
作用:設(shè)置規(guī)則執(zhí)行的優(yōu)先級(jí),值是一個(gè)數(shù)字,數(shù)字越大執(zhí)行的優(yōu)先級(jí)越高,它的值可以是一個(gè)負(fù)數(shù),默認(rèn)值是0
如果我們不手動(dòng)設(shè)置salience屬性值,則執(zhí)行順序是隨機(jī)的
no-loop防止死循環(huán)
在一個(gè)規(guī)則中如果條件滿足就對Working Memory當(dāng)中的某個(gè)Fact對象進(jìn)行修改,比如使用update將其更新到當(dāng)前的Working Memory當(dāng)中,這時(shí)候引擎會(huì)再次檢查所有的規(guī)則是否滿足條件,如果滿足會(huì)再執(zhí)行,可能會(huì)出現(xiàn)死循環(huán)
作用:用來控制已經(jīng)執(zhí)行過的規(guī)則條件再次滿足時(shí)是否再次執(zhí)行,默認(rèn)是false,如果屬性值是true,表示該規(guī)則只會(huì)被規(guī)則引擎檢查一次,如果滿足條件就執(zhí)行規(guī)則的RHS部分
注意:如果引擎內(nèi)部因?yàn)閷act更新引起引擎再次啟動(dòng)檢查規(guī)則,那么它會(huì)忽略掉所有的no-loop屬性設(shè)置為true的規(guī)則
例如以下情況:計(jì)算設(shè)置了no-loop為true也會(huì)出現(xiàn)死循環(huán)
package rules.testwordimport com.drools.test.Person rule test001 no-loop true when $p:Person(name=="張三"); then $p.setAge(50); update($p); System.out.println("設(shè)置no-loop時(shí)的效果"); endrule test002 no-loop true when $p:Person(age==50); then $p.setName("張三"); update($p); System.out.println("設(shè)置no-loop時(shí)的效果");end
date-effective日期比較小于等于
date-expires日期比較大于
Dialect方言
Enabled是否可用
lock-on-active規(guī)則執(zhí)行一次
當(dāng)在規(guī)則上使用ruleflow-group屬性或agenda-group屬性的時(shí)候,將lock-on-active屬性的值設(shè)置為true,可以避免因某些Fact對象被修改而使已經(jīng)執(zhí)行過
的規(guī)則再次被激活執(zhí)行??梢钥闯鲈搶傩耘cno-loop屬性有相似之處,no-loop屬性是為了避免Fact修改或調(diào)用了insert,retract,update之類導(dǎo)致
規(guī)則再次激活執(zhí)行,這里lock-on-active屬性也是這個(gè)作用,lock-on-active是no-loop的增強(qiáng)版。
作用:在使用ruleflow-group屬性或agenda-group屬性的時(shí)候,默認(rèn)是false,設(shè)置為true,該規(guī)則只會(huì)執(zhí)行一次
activation-group分組
agenda-greoup議程分組
規(guī)則的調(diào)用與執(zhí)行是通過StatelessSession和ksession來實(shí)現(xiàn)的,一般的順序是創(chuàng)建一個(gè)StatelessSession或ksession,
將各種經(jīng)過編譯的規(guī)則的package添加到session當(dāng)中,接下來將規(guī)則當(dāng)中可能用到的Global對象和Fact對象插入到Session當(dāng)中,
最后調(diào)用fireAllRules方法來觸發(fā),執(zhí)行規(guī)則,在沒有調(diào)用最后一步分fireAllRules方法之前,
所有的規(guī)則及插入的Fact對象都存放在Agenda表的對象當(dāng)中,這個(gè)Agenda表中的每個(gè)規(guī)則及其匹配相關(guān)的業(yè)務(wù)數(shù)據(jù)叫做Activation,
在調(diào)用fireAllRules方法后,這些Activation會(huì)依次執(zhí)行,這些位于Agenda表中的Activation的執(zhí)行順序在沒有設(shè)置相關(guān)用來
控制順序的時(shí)(比如:salience屬性),它的執(zhí)行順序是隨機(jī)不確定的。
agenda-group是用來在Agenda基礎(chǔ)上,對現(xiàn)有的規(guī)則進(jìn)行再次分組,具體的分組方法可以采用為規(guī)則添加agenda-group屬性來實(shí)現(xiàn),
agenda-group屬性的值也是一個(gè)字符串,通過這個(gè)字符串,可以將規(guī)則分為若干個(gè)agenda group,默認(rèn)情況下,引擎在調(diào)用這些
設(shè)置了agenda-group屬性的規(guī)則的時(shí)候需要指定某個(gè)agenda group得到Focus(焦點(diǎn)),這樣位于該agenda group當(dāng)中的規(guī)則才會(huì)觸發(fā)執(zhí)行,否則將不執(zhí)行
實(shí)際應(yīng)用中agenda-group可以和auto-focus屬性一起使用
auto-focus焦點(diǎn)分組
ruleflow-group規(guī)則流
Drools drl注釋的使用
單行// 多行/**/
Drools函數(shù)的使用
insert插入
語法格式:insert(new Object());
insertLogical插入
update修改
語法格式:update(Object());
retract刪除功能
drools常用方法
方法名稱 用法格式 含義
getWorkingMemory() drools.getWorkingMemory() 獲取當(dāng)前WorkingMemory對象
halt() drools.halt() 在當(dāng)前規(guī)則執(zhí)行完成之后,不再執(zhí)行其他未執(zhí)行的規(guī)則
getRule() —— 獲取當(dāng)前規(guī)則對象
insert(new Object) —— 插入指定對象
update(new Object) —— 更新指定對象
update(FactHandleObject) —— 更新指定對象
retract(new Object) —— 刪除指定對象
Drools語法篇之Global全局變量
global不是用來做數(shù)據(jù)共享的,session會(huì)影響到global的用法
注意:
1、常量值是不能改變的
2、包裝類是不能改變的
3、類似javaBean,List這類的操作,是可以改變內(nèi)容的,但內(nèi)存地址是不會(huì)變的
Drools語法篇之查詢Query
Drools語法篇之類的聲明及元數(shù)據(jù)的用法
聲明新類型:使用關(guān)鍵字declare,緊接著字段列表,和關(guān)鍵字end。
例如:
declare Address number:int streetName:String city:Stringend
聯(lián)系客服