Drools的API呼叫
在上一章節裡,小編簡單的講述了規則檔案的編輯語法與規範,讀者還沒有看過rule的執行過程,下面我們就通過例子對rule進行一下呼叫。在Drools當中,規則的編譯與執行要通過Drools提供的各種API來實現,這些API總體來講可以分為三類:規則編譯、規則收集和規則的執行。
在呼叫時,我們先要做以下幾個操作:
1、Kmodule.xml的編輯
kmodule.xml檔案放到src/main/resources/META-INF/資料夾下
程式碼的實現(具體內容)
<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"> <kbase name="kbase1" packages="rules.testwrod"> <ksession name="session"/> </kbase> </kmodule>
分析上面程式碼:
1) 一個kmodule裡面可包含多kbase,這個也是我們這個例子裡面的用例對應drl規則檔案的例子,每一個kbase都有一個name,可以取任意字串,但是不能重名。
2) 然後有一個packages,可以看到packages裡面的字串其實就是src/main/resources下面的資料夾的名稱,或者叫包名,規則引擎會根據這裡定義的包來查詢規則定義檔案。可以同時定義多個包,以逗號分隔開來就行。每一個kbase下面可以包含多個ksession,當然本例中都自定義了一個。注:packages 是以小數點進行分離的,與java中package是一樣的,指的是物理路徑,packages只能指到該值的路徑,是不能遞迴子資料夾的,這一點讀者要謹記。
3) 每一個ksession都有一個name,名字也可以是任意字串,但是也不能重複。kbase和ksession裡面的name屬性是全域性不能重複的。kbase和ksession中其實還有很多其它的屬性,每一個kbase下面可以包含多個ksession。
4) 在執行時,KieContainer會根據*Model物件來建立KieModule、KieBase、KieSession物件。其中KieModule和KieBase只會建立一次,而KieSession則有可能建立多次,因為KieSession的建立成本很低,同時KieSession包含了執行時的資料,所以可以銷燬、建立若干次。
2、API的說明,建立一個java檔案
在寫java檔案之前我們先要引用drools相關的jar包,小編再次說明一下,以下的例子都是drools6.4版本
Mavne pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.drools.modules.test</groupId>
<artifactId>drools-moudles</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>drools-moudles</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- drools 規則引擎 版本 -->
<drools.version>6.4.0.Final</drools.version>
<spring.version>4.2.6.RELEASE</spring.version>
<log4j2.version>2.5</log4j2.version>
</properties>
<!-- 依賴項定義 -->
<dependencies>
<!-- start drools -->
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-workbench-models-guided-template</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-simulator</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.jbpm</groupId>
<artifactId>jbpm-flow-builder</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-ci</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-internal</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-workbench-models-guided-dtable</artifactId>
<version>${drools.version}</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-templates</artifactId>
<version>${drools.version}</version>
</dependency>
<!-- end drools -->
</dependencies>
<build>
<testResources>
<testResource>
<directory>
${project.basedir}/src/main/resources
</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
JAVAcode
package com.drools.test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
public class TestWrod{
public static void main(String[] args) {
KieServices kss = KieServices.Factory.get();
KieContainer kc = kss.getKieClasspathContainer();
KieSession ks =kc.newKieSession("session");
int count = ks.fireAllRules();
System.out.println("總執行了"+count+"條規則");
ks.dispose();
}
}
分析java程式碼
從classpath中讀取kmodule,建立KieContainder容器。
利用kieContainer物件建立一個新的KieSession,建立session的時候我們傳入了一個name: session”,這個字串很眼熟吧,這個就是我們定義的kmodule.xml檔案中定義的ksession的name。
kieContainer根據kmodule.xml定義的ksession的名稱找到KieSession的定義,然後建立一個KieSession的例項。
KieSession就是一個到規則引擎的連結,通過它就可以跟規則引擎通訊,並且發起執行規則的操作。
然後通過kSession.fireAllRules方法來通知規則引擎執行規則
ks.dispose();最後將kiesession連線關閉
那讓我們看一下結果 如圖2-2
上面只最簡單的helloworld了,是不是很容易就懂了呢,好!那小編再增加一點點難度,我們往規則裡插入一個值,來進行一個簡單的業務判斷。
業務說明:判斷人名是張三,年齡30歲,就將該人名改為李四
實體POJO
package com.drools.test;
public class Person {
private String name;
private int age;
private String desc;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
….此處省略get set 方法,但讀者做例子時一定要加上哦
規則程式碼如下:
Person.drl
package rules.testwrod
import com.drools.test.Person
rule test001
when
$p:Person(name=="張三",age==30);
then
$p.setName("李四");
System.out.println("改完後的名字"+$p.getName());
end
在API程式碼說明
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
public class TestWrod
{
public static void main(String[] args)
{
KieServices kss = KieServices.Factory.get();
KieContainer kc = kss.getKieClasspathContainer();
KieSession ks =kc.newKieSession("session");
Person person=new Person("張三",30);
FactHandle insert = ks.insert(person);
int count = ks.fireAllRules();
System.out.println("總執行了"+count+"條規則");
System.out.println(person.getName());
ks.dispose();
}
}
那讓我們看一下結果 如圖2-3
(圖2-3)
在控制檯上我們可以看到是我們想要的結果。在規則裡變了,java中的Bean也發生了變化,這就滿意了我們業務上的要求?
小編為什麼在最後打了一個問號呢,我們的真的改變了fact物件嘛,是我們真正想要的結果嘛,看起來是沒問題的,控制檯也輸出,但如果我稍稍修改一下業務的話,在之前的業務上新增 並將名為李四的的年齡設定為40,那我規則就應該是這樣了
規則程式碼如下:
Person.drl
package rules.testwrod
import com.drools.test.Person
rule test001
when
$p:Person(name=="張三",age==30);
then
$p.setName("李四");
System.out.println("改完後的名字"+$p.getName());
end
rule test002
when
$p:Person(name=="李四");
then
$p.setAge(40);
System.out.println("改完後的名字"+$p.getName()+"改完後的年齡"+$p.getAge());
end
java的程式碼不變,執行結果,我們發現結果與第一次相同,難道是我們寫的程式碼沒有編譯?為什麼沒有生效呢,test001規則明明已經將Person中的name屬性改為“李四”了那為什麼值規則test002沒有執行呢,這裡小編就要鄭重的提一句了,這是因為rete的演算法問題,什麼是rete演算法呢,在後面的章節裡小編會做一個詳細的說明,好!,那小編先帶著讀者解決這個問題。其實解決起來很簡單,只要在第一個規則裡新增之前所說的update 就可以了。
將test001規則中的then中 $p.setName("李四");下方新增update($p);再次執行
那讓我們看一下結果 如圖
注:小編是這樣認為的:其實導致這個原因的是因為rete演算法的問題,簡單說明一下,rete演算法會將規則中的內容先全部加載出來,我們在規則中看似把Person的name屬性改變了,但本質中只是引用發生了改變,fact物件是沒有真正改變的。當fact物件發生真正改變時,規則將重新執行,但這樣是有風險的,容易產生死迴圈。解決方案會在rule的屬性中有說明 |
下面是小編的微信轉帳二維碼,小編再次謝謝讀者的支援,小編會更努力的
----請看下方↓↓↓↓↓↓↓
百度搜索 Drools從入門到精通:可下載開源全套Drools教程
深度Drools教程不段更新中:
更多Drools實戰陸續釋出中………
掃描下方二維碼關注公眾號 ↓↓↓↓↓↓↓↓↓↓