一、理解
在drools
中存在2種session,一種是有狀態的Session (Stateful Session
),另外一種一種是無狀態的Session (Stateless Session
)。
1、那麼他們2者之間有什麼不同呢?
2、何時該使用有狀態的Session,何時該使用無狀態的Session?此處簡單說一下我的理解
。
1、有狀態Session
有狀態 session 是使用推理對fact 物件隨時間進行迭代更改的會話。 在有狀態的 session中,來自 session的先前呼叫(先前的會話狀態)的資料在會話呼叫之間保留,而在無狀態的 session中,該資料被丟棄。
2、無狀態Session
無狀態 session 是不會使用推理對fact 物件隨時間進行迭代更改的會話。 無狀態 Session 的先前呼叫的資料在會話之間不會保留的。
解釋:
針對無狀態 session 是不會使用推理對fact 物件隨時間進行迭代更改的會話
的理解,我的理解是 針對Java Api
來使用的,
1、在無狀態的Session中,只有execute
方法,多次呼叫execute
方法,在上次execute
方法不會影響下次execute
方法的執行。
2、而在drl
檔案中使用insert
或update
或modify
或delete
等方法時,會導致工作記憶體的物件更新,導致規則的重新匹配。
3、那麼何時使用不同的Session呢?
1、如果說我們只是驗證一下規則,那麼用無狀態的Session。
比如:
- 驗證使用者是否有開銀行卡的條件。
- 計算訂單金額的折扣。
即一步就可以完成。
2、如果說我們的規則需要多步來完成,則可以用有狀態的Session。
比如:
- 向Session中插入Fact物件A,然後觸發規則。
- 執行一段Java程式碼
- 向Session中插入Fact物件B,然後觸發規則,此時的規則需要依賴上一步規則的資料。
即需要關聯的多步來完成。
二、需求
我們自己有一個Count
物件,該物件存在cnt
和name
2個屬性。
規則檔案中存在如下2個規則
規則一:
如果工作記憶體中存在Count
物件,則將Count
物件的cnt
屬性加1
規則二:
如果工作記憶體中存在2
個Count
物件,一個物件的name=count-01
另一個物件的name=count-02
則輸出ok
字串。
針對有狀態Session和無狀態Session,看結果有什麼不同。
三、實現步驟
1、專案結構說明
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、編寫Count類
@Data
@AllArgsConstructor
public class Counter {
/**
* 名稱
*/
private String name;
/**
* 計數
*/
private Integer cnt;
}
就是一個普通的java物件。
4、編寫kmodule.xml檔案
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kabse-01" packages="rules.stateful" default="false">
<!--
type="stateful" 表示有狀態的session
-->
<ksession name="stateful-session" default="false" type="stateful"/>
</kbase>
<kbase name="kabse-02" packages="rules.stateless" default="false">
<!--
type="stateless" 表示無狀態的session
-->
<ksession name="stateless-session" default="false" type="stateless"/>
</kbase>
</kmodule>
此處需要注意ksession
中type
的值,無狀態Session和有狀態Session的值不一致,不寫type,預設就是有狀態Session。
5、編寫規則檔案
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
// 如果工作記憶體中同時存在 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執行結果
1、因為是有狀態的Session,在多次fireAllRules
的時候,上次插入到工作記憶體的物件還是存在的。即Session的資料保留了
。
2、有狀態Session在執行完之後,必須要呼叫dispose
方法,避免記憶體洩漏。
7、Stateless Session執行結果
無狀態的Session,因為會丟失Session的資料,所以ok
沒有輸出出來。
四、注意事項
1、在drl
檔案中,使用insert\update\modify\delete
等方法時,都在導致規則的重新匹配。
2、Java
程式碼中是否可以獲取stateful session
或stateless session
是有ksession
中的type
的值決定的。
3、stateless session
在execute
執行完之後,會清除工作記憶體中的資料,而stateful session
在fireAllRules
則不會清除,除非呼叫了dispose
方法。
4、個人理解有狀態和無狀態從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