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
的状况彻底相同。