Drools是一款基于Java的開源規(guī)則引擎
實現(xiàn)了將業(yè)務決策從應用程序中分離出來簿寂。
優(yōu)點:
1钦椭、簡化系統(tǒng)架構拧额,優(yōu)化應用
2、提高系統(tǒng)的可維護性和維護成本
3彪腔、方便系統(tǒng)的整合
4侥锦、減少編寫“硬代碼”業(yè)務規(guī)則的成本和風險
Drools的基本工作工程
我們需要傳遞進去數(shù)據(jù),用于規(guī)則的檢查德挣,調用外部接口恭垦,同時還可能獲取規(guī)則執(zhí)行完畢之后得到的結果
Fact對象:
指傳遞給drools腳本的對象,是一個普通的javabean格嗅,原來javaBean對象的引用番挺,可以對該對象進行讀寫操作,并調用該對象的方法
當一個java bean插入到working Memory(內存存儲)中屯掖,規(guī)則使用的是原有對象的引用玄柏,規(guī)則通過對fact對象的讀寫,
實現(xiàn)對應用數(shù)據(jù)的讀寫贴铜,對其中的屬性粪摘,需要提供get和set方法瀑晒,規(guī)則中可以動態(tài)的前往working memory中插入刪除新的fact對象
Drools的基礎語法:
包路徑,引用徘意,規(guī)則體 (其中包路徑和規(guī)則體是必須的)
Drl文件內容:
例子:
hello.drl文件如下:
package rules.testword
rule "test001" when
//這里如果為空苔悦,則表示eval(true)then
System.out.println("hello word");
end
package:包路徑,該路徑是邏輯路徑(可以隨便寫椎咧,但是不能不寫玖详,最好和文件目錄同名,以(.)的方式隔開)勤讽,規(guī)則文件中永遠是第一行
rule:規(guī)則體竹宋,以rule開頭,以end結尾地技,每個文件可以包含多個rule,規(guī)則體分為3個部分:LHS秒拔,RHS莫矗,屬性 三大部分
LHS:(Left Hand Side),條件部分砂缩,在一個規(guī)則當中“when”和“then”中間的部分就是LHS部分作谚,在LHS當中,可以包含0~N個條件庵芭,如果
LHS為空的話妹懒,那么引擎會自動添加一個eval(true)的條件,由于該條件總是返回true双吆,所以LHS為空的規(guī)則總是返回true眨唬。
RHS:(Right Hand Side),在一個規(guī)則中“then”后面的部分就是RHS好乐,只有在LHS的所有條件都滿足的情況下匾竿,RHS部分才會執(zhí)行。
RHS部分是規(guī)則真正做事情的部分蔚万,滿足條件觸發(fā)動作的操作部分岭妖,在RHS可以使用LHS部分當中的定義的綁定變量名,設置的全局變量反璃、
或者是直接編寫的java代碼昵慌,可以使用import的類。
不建議有條件判斷淮蜈。
可以使用快速操作working Memory的宏函數(shù)和對象斋攀,比如insert/insertLogical,update/modify和retract就可以實現(xiàn)對當前Working Memory中的Fact對象
進行新增,修改礁芦,或者刪除蜻韭,可以使用drool宏對象悼尾,Drools還提供了kcontext的宏對象,該對象可以直接訪問當前Working Memory的KnowledgeRuntime肖方。
import:導入規(guī)則文件需要使用到的外部變量闺魏,可以導入類,也可以是這個類中的靜態(tài)方法
例如:
import com.dinpay.dpp.rcp.service.util.RuleLogUtil; 導入類
import com.dinpay.dpp.rcp.service.util.RuleLogUtil.getLog;//導入靜態(tài)方法
Drools的API調用
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)艰垂、可包含多個kbase泡仗,任意但不能重名
2)、有個packages猜憎,就是src/main/resources下面的文件夾名稱娩怎,可定義多個包,用逗號隔開
3)胰柑、ksession都一個name截亦,任意字符串但不能重名,可以有多個
4)柬讨、在運行時崩瓤、KieContainer會根據(jù)*Model對象來創(chuàng)建KieModule,KieBase踩官,KieSession對象却桶,其中KieModule和KieBase只會創(chuàng)建一次,而KieSession則可能創(chuàng)建多次
2蔗牡、API說明颖系,引入drools依賴jar包,drools-core辩越,kie-api集晚,drools-compiler
KieSession;
用于與規(guī)則引擎進行交互的會話
分為兩類:
有狀態(tài)KieSession:KieSession會在多次與規(guī)則引擎進行交互中区匣,維護會話狀態(tài)偷拔,type屬性值是stateful,
最后需要清理KieSession維護的狀態(tài)亏钩,調用dispose()方法
無狀態(tài)StatelessKieSession:StatelessKieSession隔離了每次與規(guī)則引擎的交互莲绰,不會維護會話狀態(tài),無副作用姑丑,type屬性值是stateless
應用場景:數(shù)據(jù)校驗蛤签,運算,數(shù)據(jù)過濾栅哀,消息路由震肮,任何能被描述成函數(shù)或公式的規(guī)則
Drools內部功能詳細介紹
規(guī)則文件
一個標準的規(guī)則文件的結構代碼:
package package-name(包名称龙,必須的,只限制于邏輯上的管理戳晌,若自定義查詢或者函數(shù)屬于同一個包名鲫尊,不管物理位置如何,都可以調用)
imports (需要導入的類名)
globals (全局變量)
functions (函數(shù))
queries (查詢)
rules (規(guī)則沦偎,可以多個)
package在規(guī)則文件中是第一行疫向,其他的順序可以是無序的,package對于規(guī)則文件中規(guī)則的管理只限于邏輯上的管理
規(guī)則語言
rule “name”
attributes ---->屬性
when
LHS ---->條件
then
RHS---->結果
end
一個規(guī)則包含三部分:唯有attributes部分可選豪嚎,其他都是必填信息
定義當前規(guī)則執(zhí)行的一些屬性等搔驼,比如是否可被重復執(zhí)行,過期時間侈询,生效時間等
LHS:定義當前規(guī)則的條件舌涨,如 when Message();判斷當前workingMemory中是否存在Message對象
RHS:可以寫java代碼,即當前規(guī)則條件滿足執(zhí)行的操作扔字,可以直接調用Fact對象的方法來操作應用
LHS:如果LHS部分為空泼菌,自動添加一個eval(true)操作
LHS部分是由一個或多個條件組成,條件又稱為pattern(匹配模式)啦租,多個pattern之間可以使用 and 或 or來進行連接,同時還可以使用小括號來確定pattern的優(yōu)先級
【綁定變量名:】Object(【filed 約束】)
對于一個pattern來說"綁定變量名"是可選的荒揣,如果在當前規(guī)則的LHS部分的其他pattern要使用這個對象篷角,那么可以通過為該對象綁定設定一個
綁定變量名來實現(xiàn)對其的引用,對于綁定變量的命名系任,通常的做法是為其添加一個 "$"符號作為前綴恳蹲,可以和Fact對象區(qū)分開來
綁定變量可以用于對象上,可以用于對象屬性上俩滥,"field約束"是指當前對象里相關字段的條件限制
rule "rule1"? ? when
? ? ? ? $customer:Customer()
? ? then
? ? ? ? ...
end? ? ? ? ? ?
規(guī)則中LHS部分單個pattern(模式)的情形嘉蕾。
規(guī)則中"$customer"就是綁定到Customer對象的"綁定變量名",該規(guī)則的LHS部分表示霜旧,要求Fact對象必須是Customer類型错忱,該條件滿足,那么它的LHS會返回true
rule "rule1"? ? when
? ? ? ? ? $customer:Customer(age>20,gender=="male")
? ? ? ? ? Order(customer==$customer,price>1000)
? ? then
? ? ? ? ? ...
end
第一個pattern有三個約束
1挂据、對象類型必須是Customer以清;
2、Customer的age要大于20
3崎逃、Customer的gender要是male
第二個pattern有三個約束
1掷倔、對象類型必須是Order
2、Order對應的Customer必須是前面那個Customer
3个绍、當前這個Order的price要大于1000
這兩個pattern沒有符號連接勒葱,在Drools當中沒有連接符號浪汪,默認是and,只有兩個pattern(模式)都滿足才會返回true凛虽,每行可以用";"結束
約束連接
對象內部的多個約束連接 "&&"(and),"||"(or)和","(and)來實現(xiàn)
如果記性常量的比較死遭,必須通過eval(條件)或者對象引用比較對象屬性,不能單獨引用
12個類型比較操作符 >|<,>=|<=,==|!=,contains|not contains,memberOf|not memberOf,matches|not matches
Drools屬性說明
salience優(yōu)先級
作用:設置規(guī)則執(zhí)行的優(yōu)先級涩维,值是一個數(shù)字殃姓,數(shù)字越大執(zhí)行的優(yōu)先級越高,它的值可以是一個負數(shù)瓦阐,默認值是0
如果我們不手動設置salience屬性值蜗侈,則執(zhí)行順序是隨機的
no-loop防止死循環(huán)
在一個規(guī)則中如果條件滿足就對Working Memory當中的某個Fact對象進行修改,比如使用update將其更新到當前的Working Memory當中睡蟋,這時候引擎會再次檢查所有的規(guī)則是否滿足條件踏幻,如果滿足會再執(zhí)行,可能會出現(xiàn)死循環(huán)
作用:用來控制已經(jīng)執(zhí)行過的規(guī)則條件再次滿足時是否再次執(zhí)行戳杀,默認是false该面,如果屬性值是true,表示該規(guī)則只會被規(guī)則引擎檢查一次信卡,如果滿足條件就執(zhí)行規(guī)則的RHS部分
注意:如果引擎內部因為對Fact更新引起引擎再次啟動檢查規(guī)則隔缀,那么它會忽略掉所有的no-loop屬性設置為true的規(guī)則
例如以下情況:計算設置了no-loop為true也會出現(xiàn)死循環(huán)
package rules.testwordimport com.drools.test.Person
? ? rule test001
? ? ? ? no-looptrue? ? ? ? when
$p:Person(name=="張三");
then
$p.setAge(50);
update($p);
System.out.println("設置no-loop時的效果");
end
rule test002
no-looptrue when
$p:Person(age==50);
then
$p.setName("張三");
update($p);
System.out.println("設置no-loop時的效果");
end?
date-effective日期比較小于等于
date-expires日期比較大于
Dialect方言
Enabled是否可用
lock-on-active規(guī)則執(zhí)行一次
當在規(guī)則上使用ruleflow-group屬性或agenda-group屬性的時候,將lock-on-active屬性的值設置為true傍菇,可以避免因某些Fact對象被修改而使已經(jīng)執(zhí)行過
的規(guī)則再次被激活執(zhí)行猾瘸。可以看出該屬性與no-loop屬性有相似之處丢习,no-loop屬性是為了避免Fact修改或調用了insert牵触,retract,update之類導致
規(guī)則再次激活執(zhí)行咐低,這里lock-on-active屬性也是這個作用揽思,lock-on-active是no-loop的增強版。
作用:在使用ruleflow-group屬性或agenda-group屬性的時候见擦,默認是false钉汗,設置為true,該規(guī)則只會執(zhí)行一次
activation-group分組
agenda-greoup議程分組
規(guī)則的調用與執(zhí)行是通過StatelessSession和ksession來實現(xiàn)的鲤屡,一般的順序是創(chuàng)建一個StatelessSession或ksession儡湾,
將各種經(jīng)過編譯的規(guī)則的package添加到session當中,接下來將規(guī)則當中可能用到的Global對象和Fact對象插入到Session當中执俩,
最后調用fireAllRules方法來觸發(fā)徐钠,執(zhí)行規(guī)則,在沒有調用最后一步分fireAllRules方法之前役首,
所有的規(guī)則及插入的Fact對象都存放在Agenda表的對象當中尝丐,這個Agenda表中的每個規(guī)則及其匹配相關的業(yè)務數(shù)據(jù)叫做Activation显拜,
在調用fireAllRules方法后,這些Activation會依次執(zhí)行爹袁,這些位于Agenda表中的Activation的執(zhí)行順序在沒有設置相關用來
控制順序的時(比如:salience屬性)远荠,它的執(zhí)行順序是隨機不確定的。
agenda-group是用來在Agenda基礎上失息,對現(xiàn)有的規(guī)則進行再次分組譬淳,具體的分組方法可以采用為規(guī)則添加agenda-group屬性來實現(xiàn),
agenda-group屬性的值也是一個字符串盹兢,通過這個字符串邻梆,可以將規(guī)則分為若干個agenda group,默認情況下绎秒,引擎在調用這些
設置了agenda-group屬性的規(guī)則的時候需要指定某個agenda group得到Focus(焦點)浦妄,這樣位于該agenda group當中的規(guī)則才會觸發(fā)執(zhí)行,否則將不執(zhí)行
實際應用中agenda-group可以和auto-focus屬性一起使用
auto-focus焦點分組
ruleflow-group規(guī)則流
Drools drl注釋的使用
單行// 多行/**/
Drools函數(shù)的使用
insert插入
語法格式:insert(new Object());
insertLogical插入
update修改
語法格式:update(Object());
retract刪除功能
drools常用方法
方法名稱 用法格式 含義
getWorkingMemory() drools.getWorkingMemory() 獲取當前WorkingMemory對象
halt() ? ? ? drools.halt() ?在當前規(guī)則執(zhí)行完成之后见芹,不再執(zhí)行其他未執(zhí)行的規(guī)則
getRule() ?? ? ?—— 獲取當前規(guī)則對象
insert(new Object) ?—— ? ? ? ? ? ? 插入指定對象
update(new Object) ?—— ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 更新指定對象
update(FactHandleObject) —— ? ? ? ? ? 更新指定對象
retract(new Object) —— ? ? 刪除指定對象
Drools語法篇之Global全局變量
global不是用來做數(shù)據(jù)共享的剂娄,session會影響到global的用法
注意:
1、常量值是不能改變的
2玄呛、包裝類是不能改變的
3阅懦、類似javaBean,List這類的操作徘铝,是可以改變內容的耳胎,但內存地址是不會變的
Drools語法篇之查詢Query
Drools語法篇之類的聲明及元數(shù)據(jù)的用法
聲明新類型:使用關鍵字declare,緊接著字段列表庭砍,和關鍵字end。
例如:
declare Address
? ? number:int? ? streetName:String
? ? city:String
end