Drools代替複雜業務

DROOLS

  • 具有一個易於訪問企業策略、易於調整以及易於管理的開源業務規則引擎,符合業內標準,速度快、效率高。業務分析師或審覈人員可以利用它輕鬆查看業務規則,從而檢驗是否以編碼的規則執行了所需的業務規則。
  • 用XML節點來規範IF-Then句式和事實的定義,使引擎幹起活來很舒服。而使用java、groovy等原生語言來做判斷和執行語句,讓程序員很容易過渡、移植,學習曲線很低。

規則引擎 BRMS

  • 規則引擎,全稱爲業務規則管理系統,英文名爲BRMS(即Business Rule Management System)。規則引擎的主要思想是將應用程序中的業務決策部分分離出來,並使用預定義的語義模塊編寫業務決策(業務規則),由用戶或開發者在需要時進行配置、管理。

需要注意的是規則引擎並不是具體的技術框架,而是指的一類系統,即業務規則管理系統。目前市面上具體的規則引擎產品有:drools、VisualRules、iLog等。

規則引擎實現了將業務決策從應用程序代碼中分離出來,接收數據輸入,解釋業務規則,並根據業務規則做出業務決策。規則引擎其實就是一個輸入輸出平臺。

系統中引入規則引擎後,業務規則不再以程序代碼的形式駐留在系統中,取而代之的是處理規則的規則引擎,業務規則存儲在規則庫中,完全獨立於程序。業務人員可以像管理數據一樣對業務規則進行管理,比如查詢、添加、更新、統計、提交業務的規則等。業務規則被加載到規則引擎中供應用系統調用。

使用規則引擎的優勢

  • 業務規則與系統代碼分離,實現業務規則的集中管理。
  • 在不重啓服務的情況下可隨時對業務規則進行擴展和維護。
  • 可以動態修改業務規則,從而快速響應需求變更,大大提高了對複雜邏輯代碼的可維護性。
  • 規則引擎是相對獨立的,只關心業務規則,使得業務分析人員也可以參與編輯、維護系統的業務規則。
  • 減少了硬編碼業務規則的成本和風險。
  • 使用規則引擎提供的規則編輯工具,是複雜的業務規則實現變得簡單。

規則引擎應用場景

對於一些存在比較複雜得業務規則並且業務規則會頻繁變動的系統比較適合使用規則引擎:

  • 風險控制系統————風險貸款、風險評估
  • 反欺詐項目——————銀行貸款、徵信驗證
  • 決策平臺系統————財務計算
  • 促銷平臺系統————滿減、打折、加價購 等等

Drools

drools是一款由JBoss組織提供的基於java語言開發的開源規則引擎,可以將複雜且多變的業務規則從硬編碼中解放出來,以規則腳本的形式存放在文件或特定的存儲介質中(例如存放在數據庫中),使得業務規則的變更不需要修改項目代碼、重啓服務器就可以在線上環境立即生效。

在項目中使用drools時,既可以單獨使用也可以整合spring使用。如果單獨使用只需要導入如下maven座標即可:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.6.Final</version>
</dependency>

如果我們使用IDEA開發drools應用,IDEA中已經集成了drools插件。如果使用eclipse開發drools應用還需要單獨安裝drools插件。
drools API開發步驟如下
獲取KieServices————>獲取KieContainer————>KieSession————>Insert fact————>觸發規————>關閉KieSession

示例

第一步新建一個Springboot項目
第二部引入Drools
<!--規則引擎-->
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>

第三步在resource下面新建META-INF目錄,接着創建kmodule.xml文件

第四步在resource下面新建rules目錄,接着創建以drl結尾的文件

使用drools規則引擎主要工作就是編寫規則文件,在規則文件中定義跟業務相關的業務規則,例如本案例定義的就是圖書優惠規則。規則定義好後就需要調用drools提供的API將數據提供給規則引擎進行規則模式匹配,規則引擎會執行匹配成功的規則並將計算的結果返回給我們。

可能大家會有疑問,就是我們雖然沒有在任何代碼中編寫規則的判斷邏輯,但是我們還是在規則文件中編寫了業務規則,這跟在代碼中編寫規則有什麼本質的區別呢?

使用規則引擎時業務規則可以做到動態管理。業務人員可以像管理數據一樣對業務規則進行管理,比如查詢、添加、更新、統計、提交業務規則等。這樣就可以做到在不重啓服務的情況下調整業務規則。

規則引擎構成
drools規則引擎由以下三部分構成:

  • working Memory(工作內存):drools規則引擎會從Working Memory中獲取數據並和規則文件中定義得規則進行模式匹配,所以我們開發得應用程序只需要將我們的數據插入到Working Memory中即可,例如本案例中我們調用kieSession.insert(order)就是將order對象插入到了工作內存中。
  • rule base(規則庫):我們在規則文件中定義的規則都會被加載到規則庫中。
  • Inference Engine(推理引擎)

Fact:事實,是指在drools規則應用當中,將一個普通的javaBean插入到WorkingMemory後的對象就是Fact對象。例如本案列中的order對象就屬於Fact對象。Fact對象是我們的應用和規則引擎進行數據交互的橋樑或通道。

其中Inference Engine(推理引擎)又包括:

  • Pattern matcher(匹配器):將Rule Base中的所有規則與Working Memory中的Fact對象進行模式匹配,匹配成功的規則將被激活並放入Agenda中。
  • Agenda(議程):用於存放通過匹配器進行模式匹配後被激活的規則。
  • Execution Engine(執行引擎):執行Agenda中被激活的規則。

規則引擎執行過程

1.將初始數據(fact)輸入至工作內存(Working Memory)
2.使用Pattern Matcher將規則庫中的規則(rule)和數據(fact)比較
3.如果執行規則存在衝突(conflict),及同時激活了多個規則,將衝突的規則放入衝突集合。
4.解決衝突,將激活的規則按順序放入Agenda
5.執行的Agenda中的規則。重複步驟b至e,直到執行完畢Agenda中的所有的規則。

KIE介紹

Kie大部分分類都是以Kie開頭。Kie全稱爲:Knowledge IS Everything,即"只是就是一切"的縮寫,是Jboss一系列項目的總稱。Kie的主要模塊有OptaPlanner、Drools、UberFire、jBPM。

Drools基礎語法

1.規則文件構成
在使用Drools時非常重要的一個工作就是編寫規則文件,通常規則文件的後綴爲.drl。
drl是Drools Rule language的縮寫。在規則文件中編寫具體的規則內容。
一套完整的規則文件內容構成如下:

關鍵字 描述
package 包名,只限於邏輯上的管理,同一個包名下的查詢或者函數可以直接調用
import 用於導入類或者靜態的方法
global 全局變量
function 自定義函數
query 查詢
rule end 規則體

Drools支持的規則文件,除了drl形式,還有Excel文件類型的。

規則體語法結構

規則提是規則文件內容中的重要組成部分,是進行業務規則判斷、處理業務結果的部分。
規則體語法結構如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

rule:關鍵字,表示規則開始,參數爲規則的唯一名稱。
attributes:規則屬性,是rule與when之間參數,爲可選項。
when:關鍵字,後面跟規則的條件部分
LHS(Left Hand Side):是規則的條件部分的通用名稱。它由零個或多個條件元素組成。如果LHS爲空,則它將被是爲始終爲true的條件元素。
then:關鍵字,後面跟規則的結果部分。
RHS(Right Hand Side):是規則的後果或行動部分的通用名稱。
end:關鍵字,表示一個規則結束。

註釋

在drl形式的規則文件中使用註釋和Java類中使用註釋一致,分爲單行註釋和多行註釋。
單行註釋用"//“進行標記,多行註釋以”/*“開始,以”*/"結束。如下示例:

// 規則rule1的註釋,這是一個單行的註釋
rule "rule1"
    when
    then
        System.out.println("rule觸發");
end

/*
規則rule2的註釋,
這是一個多行的註釋
*/
rule "rule2"
    when
    then
        System.out.println("rule2觸發");
end

Pattern模式匹配

前面我們已經知道了Drools中的匹配器可以將Rule Base中的所有規則與Working Memory中的fact對象進行模式匹配,那麼我們就需要在規則體的LHS部分定義規則並進行模式匹配。LHS部分由一個或者多個條件組成,條件又稱爲pattern。

pattern的語法結構爲:綁定變量名:Object(Field約束)
其中綁定變量明可以省略,通常綁定變量名的命名一般建議以$開始。如果定義了綁定變量名,就可以在規則體的RHS部分使用此綁定變量名來操作相應的Fact對象。Field約束部分是需要返回true或者false的0個或多個表達式。

例如我們的案例:

// 規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
    when
        // Order爲類型約束,originalPrice爲屬性約束
        $order:Order(originalPrice < 200 && originalPrice >= 100);
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到規則二:所購圖書總價在100到200的優惠20元");
end

通過上面的例子我們可以知道,匹配的條件爲:
1.工作內存中必須在Order這種類型的Fact對象----類型約束
2.Fact對象的originalPrice屬性值必須小於200----屬性約束
3.Fact對象的originalPrice屬性值必須大於等於100----屬性約束
以上條件必須同時滿足當前規則纔有可能被激活。

綁定變量可以用在對象上,也可以用在對象的屬性上。例如上面的例子可以改爲:

// 規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100);
    then
        System.out.println("$op =" + $op);
        $order.setRealPrice($order.getOriginalPrice - 20);
        System.out.println("成功匹配到規則二:所購圖書總價在100到200的優惠20元");
end

LHS部分還可以定義多個pattern,多個pattern之間可以使用and 或者or進行連接,也可以不寫,默認連接爲and。

// 規則二:所購圖書總價在100到200元的優惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100) and 
        $customer:Customer(age > 20 && gender == 'male');
    then
        System.out.println("$op =" + $op);
        $order.setRealPrice($order.getOriginalPrice - 20);
        System.out.println("成功匹配到規則二:所購圖書總價在100到200的優惠20元");
end

比較操作符

Drools提供的比較操作符,如下表:

符號 說明
> 大於
< 小於
>= 大於等於
<= 小於等於
== 等於
!= 不等於
contains 檢查一個Fact對象的某個屬性值是否包含一個指定的對象值
not contains 檢查一個Fact對象的某個屬性值是否不包含一個指定的對象值
memberOf 判斷一個fact對象的某個屬性是否在一個或多個集合中
not memberOf 判斷一個fact對象的某個屬性是否不在一個或多個集合中
matches 判斷一個Fact對象的屬性是否與提供的標準的java正則表達式進行匹配
not matches 判斷一個Fact對象的屬性是否不與提供的標準的java正則表達式進行匹配

前6個比較操作符和java中的完全相同,下面我們重點學習後6個比較操作符

  • contains | not contains 語法結構
    object(field[Collection/Array]contains value)
    object(field[Collection/Array] not contains value)
  • memberOf | not memberOf 語法結構
    object(field memberOf value [Collection/Array])
    object(field not memberOf value [Collection/Array])
  • matches | not matches 語法結構
    object(field matches “正則表達式”)
    object(field not matches “正則表達式”)

關鍵字

Drools關鍵字分爲:硬關鍵字(Hard Keywords)和軟關鍵字(Soft keywords).
硬關鍵字是我們在規則文件中定義包名或者規則名時明確不能使用的,否則程序會報錯。軟關鍵字雖然可以使用,但是不建議使用。
硬關鍵字包括:true、false、null
軟關鍵字包括:lock-on-active、date-effective、date-expire、no-loop、auto-focus、activation-group、agenda-group、ruleflow-group、entry-point、duration、package、import、dialect、salience、enabled、attributes、rule、extend、when、then、template、query、declare、function、global、eval、not、in、or、and、exists、forall、accumulate、collect、from、action、reverse、result、end、over、init

Drools內置方法

規則文件的RHS部分的主要作用是通過插入,刪除或修改工作內存中的Fact數據,來達到控制規則引擎執行的目的。Drools提供了一些方法可以用來操作工作內存中的數據,操作完成後規則引擎會重新進行相關規則的匹配,原來沒有匹配成功的規則在我們修改數據完成後有可能就會匹配成功了。

Update方法的作用是更新工作內存中的數據,並讓相關的規則重新匹配。在更新數據時需要注意防止發生死循環。

insert方法的作用是向工作內存中插入數據,並讓相關的規則重新匹配。

retract方法的作用是刪除工作內存中的數據,並讓相關的規則重新匹配

執行順序默認是按照編寫規則的優先級,可以使用salience來設置優先級

規則屬性

attributes

屬性名 說明
salience 指定規則行優先級
dialect 指定規則使用的語言類型,取值爲java和mvel
enabled 指定規則是否啓動
date-effective 指定規則生效時間
date-expires 指定規則失效時間
activation-group 激活分組,具有相同組名稱的規則只能有一個規則觸發
agenda-group 議程分組,只有獲取焦點的組中的規則纔有可能觸發
timer 定時器,指定規則觸發的時間
auto-focus 自動獲取焦點,一般結合agenda-group一起使用
no-loop 防止死循環
enabled屬性

enabled屬性對應的取值爲true和false,默認爲true。用於指定當前規則是否啓用,如果設置的值爲false則當前規則無論是否匹配成功都不會觸發。

dialect屬性

dialect屬性用於指定當前規則使用的語言類型,取值爲java和mvel,默認爲java。
注:mvel是一種基於java語言的表達式語言。
mvel向正則表達式一樣,有直接支持集合、數組和字符串匹配的操作符。
mvel還提供了用來配置和構造字符串的模板語言。
mvel表達式內容包括屬性表達式,布爾表達式,方法調用,變量賦值,函數定義等。

salience屬性

salience屬性用於指定規則的執行優先級,取值類型爲Integer。數值越大越優先執行。每個規則都有一個默認的執行順序,如果不設置salience屬性,規則體的執行順序爲由上到下。

no-loop屬性

no-loop屬性用於防止死循環,當規則通過update之類的函數修改了Face對象時,可能使當前規則再次被激活而導致死循環。取值類型爲Boolean,默認值爲false。

activation-group屬性

activation-group屬性是指激活分組,取值爲String類型。具有相同的分組名稱的規則只能有一個規則被觸發。
同一個分組中的多個規則如果都能匹配成功,具體哪一個最終能夠被觸發可以通過salience屬性確定。

agenda-group屬性

agenda-group屬性爲議程分組,屬於另一種可控制的規則執行方式。用戶可以通過設置agenda-group來控制規則的執行,只有獲取焦點的組中的規則纔會被觸發。

auto-focus屬性

auto-focus屬性爲自動獲取焦點,取值類型爲Boolean,默認值爲false。一般結合agenda-group屬性使用,當一個議程分組爲獲取焦點時,可以設置auto-focus屬性來控制。

timer屬性

timer屬性可以通過定時器的方式指定規則執行的時間,使用方式有兩種:

方式一:timer(int:?)
此種方式遵循java.util.Timer對象的使用方式,第一個參數表示幾秒後執行,第二個數表述每隔幾秒執行一次,第二個參數爲可選。
方式二:timer(cron:)
此種方式使用標準的unix cron表達式的使用方式來定義規則執行的時間。

date-effective屬性

date-effective屬性用於指定規則的生效時間,即只有當前系統時間大於等於設置的時間或者日期規則纔有可能觸發。默認日期格式爲:dd-MMM-yyyy。用戶也可以自定義日期格式。

date-expires屬性

date-expires屬性用於指定規則的失效時間,即只有當前系統時間小於的時間或者日期規則纔有可能觸發。默認日期格式爲:dd-MMM-yyyy。用戶也可以自定義日期格式。

Drools高級語法

關鍵字 描述
package 包名,只限於邏輯上的管理,同一個包名下的查詢或者函數可以直接調用
import 用於導入類或者靜態方法
global 全局變量
function 自定義函數
query 查詢
rule end 規則體
global全局變量

global關鍵字用於在規則文件中定義全局變量,它可以讓應用程序的對象在規則文件中能被訪問。可以用來爲規則文件提供數據或服務。

語法結構爲:global對象類型 對象名稱
在使用global定義的全局變量時有兩點需要注意:
1.如果對象類型爲包裝類型時,在一個規則中改變了global的值,那麼只針對當前規則有效,對其他規則中的global不會有影響。可以理解爲它是當前規則代碼中的global副本,規則內部修改不會影響全局的使用。
2.如果對象類型爲集合類型或javaBean時,在一個規則中改變了global的值,對java代碼和所有規則都有效。

query查詢

query查詢提供了一種查詢working memory中符合約束條件的fact對象的簡單方法。它僅包含規則文件中的LHS部分,不用指定“when”和“then”部分並且以end結束。語法如下:

query 查詢的名稱(可選參數)
    LHS
end
function函數

function關鍵字用於在規則文件中定義函數,就相當於java類中的方法一樣。可以在規則體中調用定義的函數。使用函數的好處是可以將業務邏輯集中放置在一個地方,根據需要可以對函數進行修改。
函數定義的語法結構如下:

function 返回值類型 函數名(可選參數){
    // 邏輯代碼
}
LHS加強

我們已經知道了在規則體中的LHS部分是介於when和then之間的部分,主要用於模式匹配,只有匹配結果爲true時,纔會觸發RHS部分的執行。

符合值限制 in/not in

複合值限制是指超過一種匹配值的限制條件,類似於SQL語句中的in關鍵字。Drools規則體中的LHS部分可以使用in或not in進行復合值的匹配。具體語法結構如下:
Object(field in(比較值1,比較值2…))

舉例:

$s:Student(name in ("張三","李四","王五"))
$s:Student(name not in ("張三","李四","王五"))
條件元素eval

eval用於規則體的LHS部分,並返回一個Boolean類型的值。
eval(表達式)
舉例:

eval(true)
eval(false)
eval(1 == 1)
條件元素not

not用於判斷working memory中是否存在某個Fact對象,如果不存在則返回true,如果存在則返回false。
not object(可選屬性約束)
舉例:

not Student()
not Student(age < 10)
條件元素exists

exists的作用與not相反,用於判斷Working Memory中是否存在某個Fact對象,如果存在則返回true,不存在則返回false。
exists Object(可選屬性約束)
舉例:

exists Student()
exists Student(age <10 && name != null)

在LHS部分進行條件編寫時並沒有使用exists也可以達到判斷WorkingMemory中是否存在某個符合條件的Fact元素的目的。
區別:當向Working Memory中加入多個滿足條件的Fact對象時,使用了Exists的規則執行一次,不使用exists的規則會執行多次。

規則繼承

規則之間可以使用extends 關鍵字進行規則條件部分的繼承,類似於java類之間的繼承
例如:

rule "rule_1"
    when
        Syudent(age > 10)
    then
        System.out.println("rule_1 執行了。。。。")
end

rule "rule_2" extends "rule_1" //繼承上面的規則
    when
        //此處的條件雖然只寫了一個,但是從上面的規則繼承了一個條件,所以當前規則存在兩個條件,即Student(age<20)和Student(age>10)
        Student(age <20)
    then
        System.out.println("rule_2 執行了")
end
RHS加強

RHS部分是規則體的重要組成部分,當LHS部分的條件匹配成功後,對應的RHS部分就會觸發執行。一般在RHS部分中需要進行業務處理。
在RHS部分Drools爲我們提供了一個內置對象,名稱就是drools。

halt

halt方法的作用是立即終止後面所有規則的執行

getWorkingMemory

getWorkingMemory方法的作用是返回工作內存對象

getRule

getRule方法的作用是返回規則對象。

規則文件編碼規範

在進行drl類型的規則文件編寫時儘量遵循如下規範:

  • 所有的規則文件(.drl)應統一放在一個規定的文件夾中,如:/rule文件夾
  • 書寫的每個規則應儘量加上註釋。註釋要清晰明瞭,言簡意賅
  • 同一類型的對象儘量放在一個規則文件中。如所有Student類型的對象儘量放在一個規則文件中
  • 規則結果部分(RHS)儘量不要有條件語句,如if(…),儘量不要有複雜的邏輯和深層次的嵌套語句
  • 每個規則最好都加上salience屬性,明確執行順序
  • Drools默認dialect爲“java”,儘量避免使用dialect “mvel”

Spring 整合Drools

在項目中使用Drools時往往會跟Spring整合來使用。
第一步:創建maven工程Drools_spring並配置pom.xml

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools</artifactId>
    <version>7.10.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.10.0.Final</version>
    <!--注意:此處必須排除傳遞過來的依賴,否則會跟我們自己導入的spring jar包產生衝突-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>

建立spring.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:kie="http://drools.org/schema/kie-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://drools.org/schema/kie-spring
                            http://drools.org/schema/kie-spring.xsd">

    <kie:kmodule id="kmodule">
        <kie:kbase name="kbase" packages="rules">
            <!--package 代表目錄-->
            <kie:ksession name="ksession"></kie:ksession>
        </kie:kbase>
    </kie:kmodule>
    <bean class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"></bean>
</beans>

SpringBoot集成Drools
首先引入相關jar包

<!--規則引擎-->
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-templates</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-api</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.10.0.Final</version>
    <!--注意:此處必須排除傳遞過來的依賴,否則會跟我們自己導入的spring jar包產生衝突-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>

相關配置文件

package com.panion.space.config;

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

/**
 * @ClassName DroolsConfig
 * @Description TODO
 * @Version 1.0
 */
@Configuration
public class DroolsConfig {

	private static final String RULES_PATH = "rules/";

	private final KieServices kieServices = KieServices.Factory.get();

	@Bean
	@ConditionalOnMissingBean
	public KieFileSystem kieFileSystem()throws IOException{
		KieFileSystem kieFileSystem = kieServices.newKieFileSystem();

		ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
		Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
		String path = null;
		for(Resource file : files){
			path = RULES_PATH + file.getFilename();
			kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
		}
		return kieFileSystem;
	}

	@Bean
	@ConditionalOnMissingBean
	public KieContainer kieContainer() throws IOException{
		KieRepository kieRepository = kieServices.getRepository();
		kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
		KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
		kieBuilder.buildAll();
		return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
	}
	@Bean
	@ConditionalOnMissingBean
	public KieBase kieBase() throws IOException{
		return kieContainer().getKieBase();
	}
	@Bean
	@ConditionalOnMissingBean
	public KModuleBeanFactoryPostProcessor kiePostProcessor() throws IOException{
		return new KModuleBeanFactoryPostProcessor();
	}
}

WorkBench

簡介
WorkBench是Kie組件中的元素,也稱爲KIE-WB,是Drools-WB與HBPM-WB的結合體。它是一個可視化的規則編輯器。WorkBench其實就是一個war包,安裝到tomcat中就可以運行。使用WorkBench可以在瀏覽器中創建數據對象、創建規則文件、創建測試場景並將規則部署到maven倉庫供其他應用使用。

1.下載tomcat8
2.下載workbench war包 https://download.jboss.org/drools/release/7.6.0.Final/kie-drools-wb-7.6.0.Final-tomcat8.war
3.需要3個jar包,放到tomcat/lib下面
kie-tomcat-integration-7.10.0.Final.jar
javax.security.jacc-api-1.5.jar
slf4j-api-1.7.25.jar
4.tomcat/bin目錄下創建setenv.bat

CATALINA_OPTS="-Xmx512M \
    -Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-drools-wb/WEB-INF/classes/login.config \
    -Dorg.jboss.logging.provider=jdk"

5.在tomcat/conf/server.xml文件中host標籤之間加入代碼

<Valve className="org.kie.integration.tomcat.JACCValve" />

6.在tomcat/conf/tomcat-users.xml文件中添加角色用戶

<tomcat-users >
  <role rolename="admin"/>
  <user username="admin" password="admin" roles="admin"/>
</tomcat-users>

workbench可以操作創建類、規則文件、檢驗規則文件、創建測試場景、構建、部署

我們可以在idea中開發項目不編寫規則文件,規則文件我們通過workbench開發安裝部署到maven倉庫中,我們自己開發的項目只需要遠程加載maven倉庫中的jar包就可以完成規則的調用。這種開發方式的好處是我們的應用可以和業務規則完全分離,同時通過workbench修改規則後我們的應用不需要任何修改就可以加載到最新的規則從而實現規則的動態變更。

決策表

Drools除了支持drl形式的文件外還支持xls格式文件(即Excel文件)。這種xls格式的文件通常稱爲決策表(decision table)。
決策表是一個“精確而緊湊的”表達條件邏輯方式,非常適合商業級別的規則。決策表與現有的drl文件可以無縫替換。Drools提供了相應的API可以將xls文件編譯爲drl格式的字符串。

關鍵字 說明 是否必須
ReleSet 相當於drl文件中的package 必須,只能有一個如果沒有設置RuleSet對應值則使用默認值rule_table
Sequential 取值爲boolean類型。true表示規則按照表格自上到下的順序執行,,false表示亂序 可選
Import 相當於drl文件中的import,如果引入多個類則類之間用逗號分隔 可選
Variables 相當於drl文件中的global,用於定義全局變量,如果有多個全局變量則中間用逗號分離 可選
RuleTable 它指示了後面將會有一批rule,RuleTable的名稱將會作爲以後生成rule的前綴 必須
CONDITION 規則條件關鍵字,相當於drl文件中的when。下面兩行則表示LHS部分,第三行則爲註釋行,不計爲規則部分,從第四行開始,每一行表示一條規則 每個規則表至少有一個
ACTION 規則結果關鍵字,相當於drl文件中的then 每個規則表至少有一個
NO-LOOP 相當於drl文件中的no-loop 可選
AGENDA-GROUP 相當於drl文件中的agenda-group 可選

在決策表中還經常使用到佔位符,語法爲$後面加數字,用於替換每條規則中設置的具體值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章