Drools學(xué)習(xí)筆記

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對(duì)象:

指傳遞給drools腳本的對(duì)象,是一個(gè)普通的javabean,原來javaBean對(duì)象的引用,可以對(duì)該對(duì)象進(jìn)行讀寫操作,并調(diào)用該對(duì)象的方法

當(dāng)一個(gè)java bean插入到working Memory(內(nèi)存存儲(chǔ))中,規(guī)則使用的是原有對(duì)象的引用,規(guī)則通過對(duì)fact對(duì)象的讀寫,

實(shí)現(xiàn)對(duì)應(yīng)用數(shù)據(jù)的讀寫,對(duì)其中的屬性,需要提供get和set方法,規(guī)則中可以動(dòng)態(tài)的前往working memory中插入刪除新的fact對(duì)象

Drools的基礎(chǔ)語法:

包路徑,引用,規(guī)則體 (其中包路徑和規(guī)則體是必須的)

Drl文件內(nèi)容:

例子:

hello.drl文件如下:

package rules.testword

rule "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ù)和對(duì)象,比如insert/insertLogical,update/modify和retract就可以實(shí)現(xiàn)對(duì)當(dāng)前Working Memory中的Fact對(duì)象

進(jìn)行新增,修改,或者刪除,可以使用drool宏對(duì)象,Drools還提供了kcontext的宏對(duì)象,該對(duì)象可以直接訪問當(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對(duì)象來創(chuàng)建KieModule,KieBase,KieSession對(duì)象,其中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對(duì)于規(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對(duì)象

RHS:可以寫java代碼,即當(dāng)前規(guī)則條件滿足執(zhí)行的操作,可以直接調(diào)用Fact對(duì)象的方法來操作應(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 約束】)

對(duì)于一個(gè)pattern來說"綁定變量名"是可選的,如果在當(dāng)前規(guī)則的LHS部分的其他pattern要使用這個(gè)對(duì)象,那么可以通過為該對(duì)象綁定設(shè)定一個(gè)

綁定變量名來實(shí)現(xiàn)對(duì)其的引用,對(duì)于綁定變量的命名,通常的做法是為其添加一個(gè) "$"符號(hào)作為前綴,可以和Fact對(duì)象區(qū)分開來

綁定變量可以用于對(duì)象上,可以用于對(duì)象屬性上,"field約束"是指當(dāng)前對(duì)象里相關(guān)字段的條件限制

rule "rule1"? ? when

? ? ? ? $customer:Customer()

? ? then

? ? ? ? ...

end? ? ? ? ? ?

規(guī)則中LHS部分單個(gè)pattern(模式)的情形。

規(guī)則中"$customer"就是綁定到Customer對(duì)象的"綁定變量名",該規(guī)則的LHS部分表示,要求Fact對(duì)象必須是Customer類型,該條件滿足,那么它的LHS會(huì)返回true

rule "rule1"? ? when

? ? ? ? ? $customer:Customer(age>20,gender=="male")

? ? ? ? ? Order(customer==$customer,price>1000)

? ? then

? ? ? ? ? ...

end

  第一個(gè)pattern有三個(gè)約束

1、對(duì)象類型必須是Customer;

2、Customer的age要大于20

3、Customer的gender要是male

第二個(gè)pattern有三個(gè)約束

1、對(duì)象類型必須是Order

2、Order對(duì)應(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é)束

約束連接

對(duì)象內(nèi)部的多個(gè)約束連接 "&&"(and),"||"(or)和","(and)來實(shí)現(xiàn)

如果記性常量的比較,必須通過eval(條件)或者對(duì)象引用比較對(duì)象屬性,不能單獨(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ī)則中如果條件滿足就對(duì)Working Memory當(dāng)中的某個(gè)Fact對(duì)象進(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)閷?duì)Fact更新引起引擎再次啟動(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-looptrue? ? ? ? when

      $p:Person(name=="張三");

     then

      $p.setAge(50);

      update($p);

      System.out.println("設(shè)置no-loop時(shí)的效果");

  end

rule test002

  no-looptrue  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對(duì)象被修改而使已經(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對(duì)象和Fact對(duì)象插入到Session當(dāng)中,

    最后調(diào)用fireAllRules方法來觸發(fā),執(zhí)行規(guī)則,在沒有調(diào)用最后一步分fireAllRules方法之前,

    所有的規(guī)則及插入的Fact對(duì)象都存放在Agenda表的對(duì)象當(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ǔ)上,對(duì)現(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對(duì)象

halt()       ? ? ? drools.halt()          ?在當(dāng)前規(guī)則執(zhí)行完成之后,不再執(zhí)行其他未執(zhí)行的規(guī)則

getRule()     ?? ? ?——             獲取當(dāng)前規(guī)則對(duì)象

insert(new Object)   ?——          ? ? ? ? ? ? 插入指定對(duì)象

update(new Object)  ?—— ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 更新指定對(duì)象

update(FactHandleObject) ——          ? ? ? ? ? 更新指定對(duì)象

retract(new Object)  ——             ? ? 刪除指定對(duì)象

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:String

end

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容