6.0引入了一種新的配置和約定方法來構建知識庫,而不是在5.x中使用編程構建器方法,構建器仍然可使用,由於它用於工具集成。編程
構建如今使用Maven,並與Maven實踐保持一致,KIE項目或模塊只是一個Maven Java項目或模塊,另外還有一個元數據文件META-INF/kmodule.xml,kmodule.xml文件是選擇資源到知識庫並配置這些知識庫和會話的描述符,還有經過Spring和OSGi藍圖提供的XML支持。api
雖然標準Maven能夠構建和打包KIE資源,但它不會在構建時提供驗證,有一個Maven插件,推薦使用它來得到構建時驗證,插件還生成許多類,使運行時加載速度更快。緩存
示例項目佈局和Maven POM描述符在屏幕截圖中進行了說明:session
KIE使用默認值來最小化配置的數量,一個空的kmodule.xml是最簡單的配置,必須始終有一個kmodule.xml文件,即便是空的,由於它用於發現JAR及其內容。less
Maven能夠經過「mvn install
」將一個KieModule部署到本地機器上,本地機器上的全部其餘應用程序都使用它,或者它能夠「mvn deploy
」將KieModule推到遠程Maven存儲庫中,構建應用程序將拉取KieModule並在過程當中填充本地Maven存儲庫。dom
JAR能夠以兩種方式部署,要麼像Maven依賴項清單中的其餘JAR同樣添加到類路徑,要麼在運行時動態加載它們,KIE將掃描類路徑以找到全部包含kmodule.xml的jar文件,每一個發現的JAR都由KieModule接口表示。術語類路徑KieModule和動態KieModule用於引用這兩種加載方法,雖然動態模塊支持並行版本控制,可是類路徑模塊不支持,此外,一旦模塊在類路徑上,就不能動態加載其餘版本。maven
API的詳細參考資料將包含在下一節中,沒有耐心的人能夠直接跳轉到示例部分,這對於不一樣的用例來講是至關容易理解的。ide
Kie項目具備普通Maven項目的結構,惟一的特色是包含kmodule.xml文件,以聲明的方式定義能夠從中建立的KieBase
和KieSession
,這個文件必須放在Maven項目的resources/META-INF文件夾中,而全部其餘Kie工件,如DRL或Excel文件,必須存儲在resources文件夾中或其下的任何其餘子文件夾中。函數
因爲全部配置方面都提供了有意義的默認值,因此最簡單的kmodule.xml文件能夠僅包含一個空的kmodule標記,以下所示:工具
<?xml version="1.0" encoding="UTF-8"?> <kmodule xmlns="http://www.drools.org/xsd/kmodule"/>
這樣,kmodule將包含一個默認的KieBase
,存儲在resources文件夾或其任何子文件夾下的全部Kie資源都將被編譯並添加到其中,爲了觸發這些工件的構建,爲它們建立一個KieContainer
就足夠了。
對於這個簡單的例子,建立一個KieContainer
就足夠了,它能夠讀取從類路徑構建的文件:
KieServices kieServices = KieServices.Factory.get(); KieContainer kContainer = kieServices.getKieClasspathContainer();
KieServices
是一個能夠訪問全部Kie構建和運行時設施的接口:
經過這種方式,全部Java源和Kie資源都被編譯並部署到KieContainer
中,而KieContainer
使其內容在運行時可用。
如前一節所述,kmodule.xml文件是能夠聲明地配置能夠從KIE項目建立的KieBase
和KieSession
的地方。
特別是KieBase
是應用程序全部知識定義的存儲庫,它將包含規則、流程、函數和類型模型。KieBase
自己不包含數據,相反,會話是從KieBase
建立的,KieBase
中能夠插入數據,從KieBase
中能夠啓動流程實例。建立KieBase
可能很重,而建立會話很是輕,所以建議在可能的狀況下緩存KieBase
,以容許重複建立會話。然而,終端用戶一般沒必要擔憂,由於KieContainer
已經自動提供了這種緩存機制。
相反,KieSession
存儲並在運行時數據上執行,它是由KieBase
建立的,若是在kmodule.xml文件中定義了它,則更容易從KieContainer
直接建立。
kmodule.xml容許定義和配置一個或多個KieBase
,併爲每一個KieBase
建立全部不一樣的KieSession
,以下面的示例所示:
<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.drools.org/xsd/kmodule"> <configuration> <property key="drools.evaluator.supersetOf" value="org.mycompany.SupersetOfEvaluatorDefinition"/> </configuration> <kbase name="KBase1" default="true" eventProcessingMode="cloud" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg1"> <ksession name="KSession2_1" type="stateful" default="true"/> <ksession name="KSession2_2" type="stateless" default="false" beliefSystem="jtms"/> </kbase> <kbase name="KBase2" default="false" eventProcessingMode="stream" equalsBehavior="equality" declarativeAgenda="enabled" packages="org.domain.pkg2, org.domain.pkg3" includes="KBase1"> <ksession name="KSession3_1" type="stateful" default="false" clockType="realtime"> <fileLogger file="drools.log" threaded="true" interval="10"/> <workItemHandlers> <workItemHandler name="name" type="org.domain.WorkItemHandler"/> </workItemHandlers> <listeners> <ruleRuntimeEventListener type="org.domain.RuleRuntimeListener"/> <agendaEventListener type="org.domain.FirstAgendaListener"/> <agendaEventListener type="org.domain.SecondAgendaListener"/> <processEventListener type="org.domain.ProcessListener"/> </listeners> </ksession> </kbase> </kmodule>
在這裏的標籤包含一個鍵-值對列表,這些鍵-值對是用於配置KieBase
構建過程的可選屬性,例如,這個樣例kmodule.xml文件定義了一個額外的自定義操做符,名爲supersetOf
,並由org.mycompany.SupersetOfEvaluatorDefinition
類實現。
在定義了這兩個KieBase
以後,就能夠從第一個KieBase
中實例化兩個不一樣類型的KieSession
,而從第二個KieBase
中實例化一個,能夠在kbase標記上定義的屬性列表,以及它們的含義和默認值以下:
屬性名稱 | 默認值 | 承認的值 | 含義 |
---|---|---|---|
name | none | 任何值 | 從KieContainer檢索此KieBase的名稱,這是惟一的強制屬性。 |
includes | none | 任何逗號分隔的列表 | 這個kmodule中包含的其餘KieBase的逗號分隔列表,全部這些KieBase的構件也將包括在這。 |
packages | all | 任何逗號分隔的列表 | 默認狀況下,resources文件夾下的全部Drools構件(任何級別)都包含在KieBase中,此屬性容許將在此KieBase中編譯的構件限制爲僅屬於包列表的構件。 |
default | false | true,false | 定義這個KieBase是不是這個模塊的默認值,所以能夠從KieContainer建立它,而不向它傳遞任何名稱,每一個模塊中最多能夠有一個默認的KieBase。 |
equalsBehavior | identity | identity,equality | 定義當一個新事實插入到工做內存中時,Drools的行爲。使用identity,它老是建立一個新的FactHandle,除非同一個對象尚未出如今工做內存中,而只有在新插入的對象與已經存在的事實不相等(根據其相等的方法)時,它才相等。 |
eventProcessingMode | cloud | cloud,stream | 在雲模式下編譯時,KieBase將事件視爲正常事實,而在流模式下則容許對它們進行時間推理。 |
declarativeAgenda | disabled | disabled,enabled | 定義聲明性議程是否啓用。 |
相似地,ksession標籤的全部屬性(固然名字除外)都有有意義的默認值,下表列出並描述了它們:
屬性名稱 | 默認值 | 承認的值 | 含義 |
---|---|---|---|
name | none | 任何值 | KieSession的惟一名稱,用於從KieContainer提取KieSession,這是惟一的強制屬性。 |
type | stateful | stateful,stateless | 有狀態會話容許迭代地使用工做內存,而無狀態會話是使用提供的數據集一次性在工做內存中執行。 |
default | false | true,false | 定義這個KieSession是不是這個模塊的默認值,所以它能夠從KieContainer建立,而無需傳遞任何名稱,在每一個模塊中,每種類型最多能夠有一個默認的KieSession。 |
clockType | realtime | realtime,pseudo | 定義事件時間戳是由系統時鐘決定仍是由應用程序控制的psuedo時鐘決定,這個時鐘對於時間規則的單元測試特別有用。 |
beliefSystem | simple | simple,jtms,defeasible | 定義KieSession所使用的信賴系統的類型。 |
正如前面的kmodule.xml示例所述,還能夠在每一個KieSession
上聲明建立一個文件(或控制檯)記錄器、一個或多個WorkItemHandler
和一些監聽器,這些監聽器能夠是3種不一樣的類型:ruleRuntimeEventListener
,agendaEventListener
,processEventListener
。
在定義了相似於前一個示例中的kmodule.xml以後,如今從KieContainer
可使用它們的名稱簡單地檢索KieBase
和KieSession
。
KieServices kieServices = KieServices.Factory.get(); KieContainer kContainer = kieServices.getKieClasspathContainer(); KieBase kBase1 = kContainer.getKieBase("KBase1"); KieSession kieSession1 = kContainer.newKieSession("KSession2_1"); StatelessKieSession kieSession2 = kContainer.newStatelessKieSession("KSession2_2");
須要注意的是,因爲KSession2_1
和KSession2_2
屬於兩種不一樣的類型(第一種是有狀態的,而第二種是無狀態的),所以須要根據KieContainer
聲明的類型調用兩種不一樣的方法。若是請求KieSession
給KieContainer
的類型與kmodule.xml文件中聲明的類型不一致,KieContainer
將拋出一個RuntimeException
。另外,因爲KieBase
和KieSession
已經被標記爲default,因此在不傳遞任何名字的狀況下,能夠從KieContainer
那裏獲得它們。
KieContainer kContainer = ... KieBase kBase1 = kContainer.getKieBase(); // returns KBase1 KieSession kieSession1 = kContainer.newKieSession(); // returns KSession2_1
因爲Kie項目也是Maven項目,所以在pom.xml文件中聲明的groupId、artifactId和version用於生成一個ReleaseId
,用於在應用程序中惟一標識該項目,這容許經過簡單地將ReleaseId
傳遞給KieServices
來從項目中建立一個新的KieContainer
。
KieServices kieServices = KieServices.Factory.get(); ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "myartifact", "1.0" ); KieContainer kieContainer = kieServices.newKieContainer( releaseId );
Maven的KIE插件確保構件資源獲得驗證和預編譯,建議在任什麼時候候都使用它,要使用該插件,只需將其添加到Maven pom的構建部分。xml並經過使用包裝kjar激活它。要使用該插件,只需將其添加到Maven pom.xml的build部分,並經過使用打包kjar
激活它。
<packaging>kjar</packaging> ... <build> <plugins> <plugin> <groupId>org.kie</groupId> <artifactId>kie-maven-plugin</artifactId> <version>7.7.0.Final</version> <extensions>true</extensions> </plugin> </plugins> </build>
這個插件支持全部Drools/jBPM knowledge資源。可是,若是你在Java類中使用特定的KIE註解,例如@kie.api.Position
,你須要在kie-api
上添加編譯時依賴到你的項目。咱們建議對全部其餘的KIE依賴項使用提供的做用域,這樣,kjar就會盡量保持輕量級,而不依賴於任何特定的KIE版本。
在不使用Maven插件的狀況下構建KIE模塊將把全部資源複製到生成的JAR中,當運行時加載JAR時,它將嘗試構建全部資源,若是存在編譯問題,它將返回null KieContainer,它還將編譯開銷推到運行時,通常來講,這是不推薦的,並且Maven插件應該老是被使用。
還能夠經過編程方式定義屬於KieModule的KieBase
和KieSession
,而不是kmodule.xml文件中的聲明性定義。一樣的編程API還容許顯式地添加包含Kie構件的文件,而不是自動從項目的resources文件夾中讀取它們。爲此,有必要建立一個KieFileSystem
(一種虛擬文件系統),並將項目中包含的全部資源添加到其中。
像全部其餘Kie核心組件同樣,你能夠從KieServices
得到KieFileSystem
的實例,kmodule.xml配置文件必須添加到文件系統中,這是一個強制性的步驟。Kie還提供了一個由KieModuleModel
實現的方便的fluent API,以編程方式建立這個文件。
爲了在實踐中作到這一點,有必要從KieServices
中建立一個KieModuleModel
,使用所需的KieBase
和KieSession
配置它,轉換到XML,並將XML添加到KieFileSystem
,這個過程以下例所示:
KieServices kieServices = KieServices.Factory.get(); KieModuleModel kieModuleModel = kieServices.newKieModuleModel(); KieBaseModel kieBaseModel1 = kieModuleModel.newKieBaseModel( "KBase1 ") .setDefault( true ) .setEqualsBehavior( EqualityBehaviorOption.EQUALITY ) .setEventProcessingMode( EventProcessingOption.STREAM ); KieSessionModel ksessionModel1 = kieBaseModel1.newKieSessionModel( "KSession1" ) .setDefault( true ) .setType( KieSessionModel.KieSessionType.STATEFUL ) .setClockType( ClockTypeOption.get("realtime") ); KieFileSystem kfs = kieServices.newKieFileSystem(); kfs.writeKModuleXML(kieModuleModel.toXML());
此時,還須要經過它的fluent API向KieFileSystem
添加其餘全部構成項目的Kie構件,這些構件必須添加到相應的Maven項目的相同位置。
KieFileSystem kfs = ... kfs.write( "src/main/resources/KBase1/ruleSet1.drl", stringContainingAValidDRL ) .write( "src/main/resources/dtable.xls", kieServices.getResources().newInputStreamResource( dtableFileStream ) );
這個示例代表,添加Kie構件能夠同時做爲純字符串和Resource
,在後者中,Resource
能夠由KieResources
工廠建立,也能夠由KieServices
提供,KieResources
提供了許多方便的工廠方法來將InputStream
、URL
、File
或表示文件系統路徑的String
轉換爲能夠由KieFileSystem
管理的Resource
。
一般,能夠從用於將Resource
添加到KieFileSystem
的名稱的擴展推斷出資源的類型,可是,也能夠不遵循Kie約定的文件擴展名,並顯式地爲Resource
分配特定的ResourceType
,以下所示:
KieFileSystem kfs = ... kfs.write( "src/main/resources/myDrl.txt", kieServices.getResources().newInputStreamResource( drlStream ) .setResourceType(ResourceType.DRL) );
將全部資源添加到KieFileSystem
並經過將KieFileSystem
傳遞給KieBuilder
來構建它。
當成功構建KieFileSystem
的內容時,生成的KieModule
會自動添加到KieRepository
,KieRepository
是一個單例庫,充當全部可用KieModule
的存儲庫。
在此以後,就能夠經過KieServices
爲KieModule
建立一個新的KieContainer
,使用ReleaseId
,可是,由於在這種狀況下,KieFileSystem
並不包含任何pom.xml文件(可使用KieFileSystem.writePomXML
方法添加xml文件),Kie不能肯定KieModule
的ReleaseId
,並給它賦一個默認值,這個默認的ReleaseId
能夠從KieRepository
得到,用來識別KieRepository
內部的KieModule
,下面的示例展現了整個過程。
KieServices kieServices = KieServices.Factory.get(); KieFileSystem kfs = ... kieServices.newKieBuilder( kfs ).buildAll(); KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
在這一點上,能夠從這個KieContainer
得到KieBase
並建立新的KieSession
,這與直接從類路徑建立KieContainer
的狀況徹底相同。