一、equality modes介紹
在drools
中存在如下2種equality modes。
1、identity模式
identity
:這是預設的情況。drools引擎使用IdentityHashMap
儲存所有插入到工作記憶體中的Fact
物件。對於每次插入一個新的物件,則會返回一個新的FactHandle
物件。如果是重複插入物件,則返回已經存在的FactHandle
物件。
舉例:
Person p1 = new Person("zhangsan", 20, "湖北羅田");
Person p2 = new Person("zhangsan", 20, "湖北黃岡羅田");
FactHandle factHandle1 = kieSession.insert(p1);
FactHandle factHandle2 = kieSession.insert(p2);
FactHandle factHandle3 = kieSession.insert(p2);
針對以上例子, factHandle1 != factHandle2
但是 factHandle2 == factHandle3
。即工作記憶體中會存在2個Person
物件。
2、equality模式
equality
:drools引擎使用HashMap
儲存所有插入到工作記憶體中的Fact
物件。在這種模式下,如果向drools中插入一個新的物件,只有這個物件不存在(根據物件的hashcode
和equals
判斷)才會返回一個新的FactHandle
否則返回已經存在的FactHandle
。
舉例:
// 重寫了Person物件的hashcode和equals方法
Person p1 = new Person("zhangsan", 20, "湖北羅田");
Person p2 = new Person("zhangsan", 20, "湖北黃岡羅田");
FactHandle factHandle1 = kieSession.insert(p1);
FactHandle factHandle2 = kieSession.insert(p2);
FactHandle factHandle3 = kieSession.insert(p2);
針對以上例子, factHandle1 == factHandle2
但是 factHandle2 == factHandle3
。即工作記憶體中會存在1個Person
物件。
二、需求
我們存在一個Person
物件,存在如下3個屬性name,age和address
,其中重寫物件的name和age
的hashcode和equals方法。
- 多次向工作記憶體中插入物件,看產生的結果。
- 插入同一個物件看獲取到的FactHandle物件是否是同一個。
三、如何設定fact物件的equality行為
此處介紹一個通過kmodule.xml
配置的方法
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kbase-identity" packages="rules" default="false" equalsBehavior="identity">
<ksession name="ksession-01" default="false" type="stateful"/>
</kbase>
<kbase name="kbase-equality" packages="rules" default="false" equalsBehavior="equality">
<ksession name="ksession-02" default="false" type="stateful"/>
</kbase>
</kmodule>
通過上方的程式碼可知是通過配置kbase
下的equalsBehavior
屬性來配置。
其餘的配置方法,參考下圖:
四、編碼實現
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>
</dependencies>
3、編寫Person物件
public class Person {
private String name;
private Integer age;
private String address;
public Person(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name) && Objects.equals(age, person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
注意:
此物件需要重寫hashcode和equals方法。
4、編寫kmodule.xml檔案
在此配置檔案中,需要在kbase
上指定equalsBehavior
,用來確定Fact
物件的equality modes。
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
<kbase name="kbase-identity" packages="rules" default="false" equalsBehavior="identity">
<ksession name="ksession-01" default="false" type="stateful"/>
</kbase>
<kbase name="kbase-equality" packages="rules" default="false" equalsBehavior="equality">
<ksession name="ksession-02" default="false" type="stateful"/>
</kbase>
</kmodule>
注意:
需要看2個equalsBehavior
的取值
5、編寫一個規則檔案
package rules
import com.huan.drools.Person
// 定義規則
rule "rule_01"
when
$p: Person()
then
System.out.println(Thread.currentThread().getName() + " name:"+$p.getName()+" age:"+$p.getAge());
end
規則檔案中的內容很簡單,只要工作記憶體中存在Person
物件,那麼就輸出這個物件的name
和age
的值。
6、identity模式測試
1、編寫測試程式碼
public class DroolsApplication {
public static void main(String[] args) {
equalsBehaviorIdentity();
}
private static void equalsBehaviorIdentity() {
KieServices kieServices = KieServices.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();
// 注意此處的 ksession-01
KieSession kieSession = kieContainer.newKieSession("ksession-01");
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
Person p1 = new Person("zhangsan", 20, "湖北羅田");
Person p2 = new Person("zhangsan", 20, "湖北黃岡羅田");
FactHandle factHandle1 = kieSession.insert(p1);
FactHandle factHandle2 = kieSession.insert(p2);
FactHandle factHandle3 = kieSession.insert(p2);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2、執行結果
具體的解釋見上圖中的說明。
7、equality模式測試
1、編寫測試程式碼
public class DroolsApplication {
public static void main(String[] args) {
equalsBehaviorEquality();
}
private static void equalsBehaviorEquality() {
KieServices kieServices = KieServices.get();
KieContainer kieContainer = kieServices.getKieClasspathContainer();
KieSession kieSession = kieContainer.newKieSession("ksession-02");
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
Person p1 = new Person("zhangsan", 20, "湖北羅田");
Person p2 = new Person("zhangsan", 20, "湖北黃岡羅田");
FactHandle factHandle1 = kieSession.insert(p1);
FactHandle factHandle2 = kieSession.insert(p2);
FactHandle factHandle3 = kieSession.insert(p2);
kieSession.fireAllRules();
kieSession.dispose();
}
}
2、執行結果
五、結論
針對如下程式碼,看看在不同equality modes下的行為
Person p1 = new Person("zhangsan", 20, "湖北羅田");
Person p2 = new Person("zhangsan", 20, "湖北黃岡羅田");
FactHandle factHandle1 = kieSession.insert(p1);
FactHandle factHandle2 = kieSession.insert(p2);
FactHandle factHandle3 = kieSession.insert(p2);
Person
物件的hashcode和equals
方法進行重寫了,根據構造方法的前2個引數。
1、identity模式下
factHandle1 != factHandle2
因為p1和p2是2個不同的物件。 factHandle2 == factHandle3
因為是p2重複加入工作記憶體,這個時候工作記憶體中已經存在了,所以返回之前關聯的FactHandle
2、equality模式下
factHandle1 == factHandle2 == factHandle3
因為這種模式下,是需要根據物件的equals
和hashcode
方法進行比較,而Person
物件重寫了這2個方法,所以返回的是同一個。
六、完整程式碼
https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-fact-equality-modes