一、理解
在drools中存在2種session,一種是有狀態(tài)的Session (Stateful Session),另外一種一種是無(wú)狀態(tài)的Session (Stateless Session)。
1、那么他們2者之間有什么不同呢?
2、何時(shí)該使用有狀態(tài)的Session,何時(shí)該使用無(wú)狀態(tài)的Session?
此處簡(jiǎn)單說(shuō)一下我的理解。
1、有狀態(tài)Session
有狀態(tài) session 是使用推理對(duì)fact 對(duì)象隨時(shí)間進(jìn)行迭代更改的會(huì)話。 在有狀態(tài)的 session中,來(lái)自 session的先前調(diào)用(先前的會(huì)話狀態(tài))的數(shù)據(jù)在會(huì)話調(diào)用之間保留,而在無(wú)狀態(tài)的 session中,該數(shù)據(jù)被丟棄。
2、無(wú)狀態(tài)Session
無(wú)狀態(tài) session 是不會(huì)使用推理對(duì)fact 對(duì)象隨時(shí)間進(jìn)行迭代更改的會(huì)話。 無(wú)狀態(tài) Session 的先前調(diào)用的數(shù)據(jù)在會(huì)話之間不會(huì)保留的。
解釋?zhuān)?/strong>
針對(duì)無(wú)狀態(tài) session 是不會(huì)使用推理對(duì)fact 對(duì)象隨時(shí)間進(jìn)行迭代更改的會(huì)話的理解,我的理解是 針對(duì)Java Api來(lái)使用的,
1、在無(wú)狀態(tài)的Session中,只有execute方法,多次調(diào)用execute方法,在上次execute方法不會(huì)影響下次execute方法的執(zhí)行。
2、而在drl文件中使用insert或update或modify或delete等方法時(shí),會(huì)導(dǎo)致工作內(nèi)存的對(duì)象更新,導(dǎo)致規(guī)則的重新匹配。
3、那么何時(shí)使用不同的Session呢?
1、如果說(shuō)我們只是驗(yàn)證一下規(guī)則,那么用無(wú)狀態(tài)的Session。
比如:
- 驗(yàn)證用戶(hù)是否有開(kāi)銀行卡的條件。
- 計(jì)算訂單金額的折扣。
即一步就可以完成。
2、如果說(shuō)我們的規(guī)則需要多步來(lái)完成,則可以用有狀態(tài)的Session。
比如:
- 向Session中插入Fact對(duì)象A,然后觸發(fā)規(guī)則。
- 執(zhí)行一段Java代碼
- 向Session中插入Fact對(duì)象B,然后觸發(fā)規(guī)則,此時(shí)的規(guī)則需要依賴(lài)上一步規(guī)則的數(shù)據(jù)。
即需要關(guān)聯(lián)的多步來(lái)完成。
二、需求
我們自己有一個(gè)Count對(duì)象,該對(duì)象存在cnt和name2個(gè)屬性。
規(guī)則文件中存在如下2個(gè)規(guī)則
規(guī)則一:
??????如果工作內(nèi)存中存在Count對(duì)象,則將Count對(duì)象的cnt屬性加1
規(guī)則二:
??????如果工作內(nèi)存中存在2個(gè)Count對(duì)象,一個(gè)對(duì)象的name=count-01另一個(gè)對(duì)象的name=count-02則輸出ok字符串。
針對(duì)有狀態(tài)Session和無(wú)狀態(tài)Session,看結(jié)果有什么不同。
三、實(shí)現(xiàn)步驟
1、項(xiàng)目結(jié)構(gòu)說(shuō)明

2、引入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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
</dependencies>
3、編寫(xiě)Count類(lèi)
@Data
@AllArgsConstructor
public class Counter {
/**
* 名稱(chēng)
*/
private String name;
/**
* 計(jì)數(shù)
*/
private Integer cnt;
}
就是一個(gè)普通的java對(duì)象。
4、編寫(xiě)kmodule.xml文件
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kabse-01" packages="rules.stateful" default="false">
<!--
type="stateful" 表示有狀態(tài)的session
-->
<ksession name="stateful-session" default="false" type="stateful"/>
</kbase>
<kbase name="kabse-02" packages="rules.stateless" default="false">
<!--
type="stateless" 表示無(wú)狀態(tài)的session
-->
<ksession name="stateless-session" default="false" type="stateless"/>
</kbase>
</kmodule>
此處需要注意ksession中type的值,無(wú)狀態(tài)Session和有狀態(tài)Session的值不一致,不寫(xiě)type,默認(rèn)就是有狀態(tài)Session。
5、編寫(xiě)規(guī)則文件
package rules.stateful
import com.huan.drools.Counter
// 將counter中的cnt的值遞增一下
rule "stateful_rule_count_increment"
when
$counter: Counter( )
then
$counter.setCnt($counter.getCnt() + 1);
System.out.println("rule_count_increment: count name:[" + $counter.getName()+"],cnt=[" + $counter.getCnt() + "]");
end
// 如果工作內(nèi)存中同時(shí)存在 count-01 和 counter-02 則輸出ok
rule "stateful_rule_count_exists"
when
Counter(name == "count-01") and Counter(name == "count-02")
then
System.out.println("ok");
end
6、Stateful session運(yùn)行結(jié)果

1、因?yàn)槭怯袪顟B(tài)的Session,在多次fireAllRules的時(shí)候,上次插入到工作內(nèi)存的對(duì)象還是存在的。即Session的數(shù)據(jù)保留了。
2、有狀態(tài)Session在執(zhí)行完之后,必須要調(diào)用dispose方法,避免內(nèi)存泄漏。
7、Stateless Session運(yùn)行結(jié)果

無(wú)狀態(tài)的Session,因?yàn)闀?huì)丟失Session的數(shù)據(jù),所以ok沒(méi)有輸出出來(lái)。
四、注意事項(xiàng)
1、在drl文件中,使用insert\update\modify\delete等方法時(shí),都在導(dǎo)致規(guī)則的重新匹配。
2、Java代碼中是否可以獲取stateful session或stateless session是有ksession中的type的值決定的。
3、stateless session在execute執(zhí)行完之后,會(huì)清除工作內(nèi)存中的數(shù)據(jù),而stateful session在fireAllRules則不會(huì)清除,除非調(diào)用了dispose方法。
4、個(gè)人理解有狀態(tài)和無(wú)狀態(tài)從api層面更好理解。
五、完整代碼
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-session
六、參考文檔
1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#kie-sessions-con_decision-engine
2、https://www.javainuse.com/drools_states
3、https://groups.google.com/g/drools-usage/c/qYbqiS1ht4g