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