drools的簡(jiǎn)單入門案例場(chǎng)景分析
一、背景
最近在學(xué)習(xí)規(guī)則引擎drools,此處簡(jiǎn)單記錄一下drools的入門案例。
1.Drools介紹
drools是一款由JBoss組織提供的基于Java語(yǔ)言開發(fā)的開源規(guī)則引擎,可以將復(fù)雜且多變的業(yè)務(wù)規(guī)則從硬編碼中解放出來(lái),以規(guī)則腳本的形式存放在文件或特定的存儲(chǔ)介質(zhì)中(例如存放在數(shù)據(jù)庫(kù)中),使得業(yè)務(wù)規(guī)則的變更不需要修改項(xiàng)目代碼、重啟服務(wù)器就可以在線上環(huán)境立即生效。
drools官網(wǎng)地址:https://drools.org/
drools源碼下載地址:https://github.com/kiegroup/drools
-----------------------------------
Drools:概述和入門案例:http://chabaoo.cn/article/248263.htm
二、為什么要學(xué)習(xí)drools
假設(shè)我們存在如下場(chǎng)景:在我們到商店購(gòu)買衣服的時(shí)候,經(jīng)常會(huì)發(fā)生這樣的事情,購(gòu)買1件不打折,購(gòu)買2件打0.98折,購(gòu)買3件級(jí)以上打0.85折。
那么我們?cè)诖a中如果要實(shí)現(xiàn)上述功能,是不是就需要編寫if ... else語(yǔ)句,假設(shè)后期規(guī)則變了,是不是就需要修改這些if ... else語(yǔ)句,然后程序重新部署。這樣是可以實(shí)現(xiàn),但是不夠優(yōu)雅。那么我們是否可以將這些業(yè)務(wù)規(guī)則寫入到規(guī)則文件中,以后規(guī)則變更直接修改規(guī)則文件即可?而drools就可以實(shí)現(xiàn)這個(gè)功能。
三、實(shí)現(xiàn)上方這個(gè)簡(jiǎn)單的打折案例
1、引入jar包
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-bom</artifactId>
<type>pom</type>
<version>7.69.0.Final</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-mvel</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
</dependencies>2、編寫kmodule.xml配置文件
此配置文件需要放置在resources/META-INF目錄下。
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<!--
kbase 可以存在多個(gè)
name: 指定kbase的名字,需要是唯一的
packages: 包名,可以理解為到src/main/resources目錄下查找這個(gè)包名下的規(guī)則文件,多個(gè)包使用逗號(hào)分割
default: 當(dāng)前kbase是否是默認(rèn)的kbase
-->
<kbase name="shop-kabse" packages="com.huan.shop" default="false">
<!--
ksession 可以存在多個(gè)
name: 指定ksession 的名字,需要唯一
defalut: 當(dāng)前ksession在這個(gè)kbase下是否是默認(rèn)的
type: 指定當(dāng)前ksession是否是有狀態(tài)的 stateless表示是無(wú)狀態(tài)的
-->
<ksession name="shop-ksession" default="false" type="stateless"/>
<ksession name="shop-ksession-stateful" default="false" type="stateful"/>
</kbase>
</kmodule>此處我們需要關(guān)注一下 kbase下package的值,這個(gè)值需要和規(guī)則文件中的package值一致,否則會(huì)找不到規(guī)則,具體看下方。
3、編寫規(guī)則文件
1、規(guī)則文件的語(yǔ)法
包名,必須放置在第一行
package
// 引入Java中的類,需要些全限定名
import
// 定義function ,可選
function // Optional
// 定義 query ,可選
query // Optional
declare // Optional
global // Optional
// rule 關(guān)鍵字 "rule name" 規(guī)則的名字
rule "rule name"
// Attributes 屬性可選
when // 關(guān)鍵字
// Conditions 條件,可為空
then
// Actions // 匹配后執(zhí)行的結(jié)果
end // 關(guān)鍵字2、編寫規(guī)則文件
規(guī)則文件的名字無(wú)所謂,比如: book-discount.drl
// 包名,必須防止到第一行,這個(gè)名字需要和 kbase中package屬性的值一致
package com.huan.shop
/**
* 倒入類
*/
import com.huan.drools.CustomerOrder
// 定義規(guī)則
rule "shop-rule-01"
when
// 模式匹配:到工作內(nèi)存中查找CustomerOrder,并且這個(gè)對(duì)象的purchaseQuantity值需要是1,
// 如果條件成立,$order是綁定變量名,一般以$開頭,和fact對(duì)象區(qū)分開
$order:CustomerOrder(purchaseQuantity == 1)
then
System.out.println("匹配規(guī)則 shop-rule-01");
// 賦值,此處賦值后,在Java代碼中獲取獲取到賦值后的值
$order.setDiscount(1D);
end
rule "shop-rule-02"
when
$order:CustomerOrder(purchaseQuantity == 2)
then
System.out.println("匹配規(guī)則 shop-rule-02");
$order.setDiscount(0.98);
end
rule "shop-rule-03"
when
$order:CustomerOrder(purchaseQuantity >= 3)
then
System.out.println("匹配規(guī)則 shop-rule-03");
$order.setDiscount(0.85);
end3、解釋一下包名

如果 shop-discount.drl的包名修改為com.huan.shop1則會(huì)提示如下警告:
12:43:01.589 [main] WARN org.drools.compiler.kie.builder.impl.KieBuilderImpl - File 'com/huan/shop/shop-discount.drl' is in folder 'com/huan/shop' but declares package 'com.huan.shop1'. It is advised to have a correspondance between package and folder names.
四、編寫Java代碼
1、編寫一個(gè)訂單對(duì)象
此對(duì)象保存的是用戶購(gòu)買了幾件衣服和對(duì)應(yīng)的折扣。
/**
* 客戶購(gòu)買衣服的訂單,省略 getter 和 setter 方法
*
* @author huan.fu
* @date 2022/5/12 - 11:27
*/
public class CustomerOrder {
/**
* 購(gòu)買了幾件衣服
*/
private Integer purchaseQuantity;
/**
* 最終打多少折
*/
private Double discount;
public CustomerOrder(Integer purchaseQuantity) {
this.purchaseQuantity = purchaseQuantity;
}
}2、編寫測(cè)試代碼
1、無(wú)狀態(tài)測(cè)試方法statelessSessionTest規(guī)則規(guī)則2,即最終打0.98折。
2、有狀態(tài)測(cè)試方法statefulSessionTest規(guī)則規(guī)則3,即最終打0.85折。
package com.huan.drools;
import org.kie.api.KieServices;
import org.kie.api.event.rule.DebugRuleRuntimeEventListener;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.StatelessKieSession;
/**
* drools 測(cè)試類
*/
public class DroolsApplication {
public static void main(String[] args) throws InterruptedException {
// 無(wú)狀態(tài)session測(cè)試
statelessSessionTest();
// 有狀態(tài)session測(cè)試
statefulSessionTest();
}
private static void statelessSessionTest() {
// 獲取kie services
KieServices kieServices = KieServices.get();
// 獲取kie容器對(duì)象
KieContainer kieContainer = kieServices.getKieClasspathContainer();
// 獲取kie session , 此處獲取的是無(wú)狀態(tài)的session,因?yàn)?<ksession name="shop-ksession" default="false" type="stateless"/>
// 中type="stateless"就是無(wú)狀態(tài)的session
StatelessKieSession kieSession = kieContainer.newStatelessKieSession("shop-ksession");
// 創(chuàng)建一個(gè)對(duì)象,可以理解為 Fact對(duì)象,即事實(shí)對(duì)象
CustomerOrder customerOrder = new CustomerOrder(2);
// 添加監(jiān)聽器,便于觀察日志
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
// 無(wú)狀態(tài)的session只需要執(zhí)行 execute 方法即可。
kieSession.execute(customerOrder);
System.err.println("通過(guò)規(guī)則后,獲取到的折扣為:" + customerOrder.getDiscount());
}
private static void statefulSessionTest() {
// 獲取kie services
KieServices kieServices = KieServices.get();
// 獲取kie容器對(duì)象
KieContainer kieContainer = kieServices.getKieClasspathContainer();
// 獲取kie session , 此處獲取的是有狀態(tài)的session
KieSession kieSession = kieContainer.newKieSession("shop-ksession-stateful");
// 創(chuàng)建一個(gè)對(duì)象,可以理解為 Fact對(duì)象,即事實(shí)對(duì)象
CustomerOrder customerOrder = new CustomerOrder(3);
// 添加監(jiān)聽器,便于觀察日志
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
// 將customerOrder對(duì)象加入到工作內(nèi)存中
kieSession.insert(customerOrder);
// 觸發(fā)所有的規(guī)則,如果只想觸發(fā)指定的規(guī)則,則使用fireAllRules(AgendaFilter agendaFilter)方法
kieSession.fireAllRules();
// 有狀態(tài)的session一定需要調(diào)用dispose方法
kieSession.dispose();
System.err.println("通過(guò)規(guī)則后,獲取到的折扣為:" + customerOrder.getDiscount());
}
}
此處需要注意有狀態(tài)session和無(wú)狀態(tài)session寫法的區(qū)別。
五、測(cè)試結(jié)果

到此,我們使用drools實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的案例就實(shí)現(xiàn)了。
六、drools引擎的基本組件

1、Rules:我們自己定義的業(yè)務(wù)規(guī)則,比如我們自己寫的規(guī)則文件。所有規(guī)則必須至少包含觸發(fā)規(guī)則的條件和規(guī)則規(guī)定的操作。
2、Production memory:規(guī)則存儲(chǔ)在 Drools 引擎中的位置。
3、Facts:輸入或更改到 Drools 引擎中的數(shù)據(jù),Drools 引擎匹配規(guī)則條件以執(zhí)行適用規(guī)則。在規(guī)則中修改了Fact對(duì)象的值,真實(shí)的JavaBean的數(shù)據(jù)也會(huì)發(fā)生改變。
比如:當(dāng)我們調(diào)用ksession.insert(對(duì)象),那么插入的這個(gè)對(duì)象就可以理解成Facts對(duì)象。
4、Working memory:facts 在 Drools 引擎中存儲(chǔ)的位置。
5、Pattern matcher:匹配器,將Rule Base中所有的規(guī)則與Working memory中的Fact對(duì)象進(jìn)行模式匹配,匹配成功的規(guī)則將被激活并放入到Agenda中。
6、Agenda:議程,執(zhí)行Agenda中被激活的排好序的規(guī)則。
七、完整代碼
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-quickstart
八、參考文檔
到此這篇關(guān)于drools的簡(jiǎn)單入門案例的文章就介紹到這了,更多相關(guān)drools入門案例內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ElasticSearch 動(dòng)態(tài)映射實(shí)戰(zhàn)詳解
這篇文章主要為大家介紹了ElasticSearch 動(dòng)態(tài)映射實(shí)戰(zhàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
SparkSQL讀取hive數(shù)據(jù)本地idea運(yùn)行的方法詳解
這篇文章主要介紹了SparkSQL讀取hive數(shù)據(jù)本地idea運(yùn)行的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
MyBatis-Plus中使用EntityWrappe進(jìn)行列表數(shù)據(jù)倒序設(shè)置方式
這篇文章主要介紹了MyBatis-Plus中使用EntityWrappe進(jìn)行列表數(shù)據(jù)倒序設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java調(diào)用Pytorch實(shí)現(xiàn)以圖搜圖功能
這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用Pytorch實(shí)現(xiàn)以圖搜圖功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-06-06
java解決動(dòng)態(tài)配置字段需求問(wèn)題
這篇文章主要介紹了java解決動(dòng)態(tài)配置字段需求問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05

