原文地址:http://docs.jboss.org/drools/release/6.2.0.Final/drools-docs/html_single/index.html
原文前面所有的步骤都可以省略,直接从安装eclipse插件开始,安装地址是:http://docs.jboss.org/drools/release/6.2.0.Final/drools-docs/html_single/index.html
在国内现在是可以直接update,所以不需要用zip安装之类的方法。
在eclipse的Preferences中出现了一个菜单Drools,在installed Drools里面add一个Runtime(选择官网下载后解压缩的binaries目录)。
新建一个Drools Project
src/main/java新建类DroolsTest:
package com.sample;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
/**
* This is a sample class to launch a rule.
*/
public class DroolsTest {
public static final void main(String[] args) {
try {
// load up the knowledge base
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession("ksession-rules");
// go !
Message message = new Message();
message.setMessage("Hello World");
message.setStatus(Message.HELLO);
kSession.insert(message);
kSession.fireAllRules();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static class Message {
public static final int HELLO = 0;
public static final int GOODBYE = 1;
private String message;
private int status;
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
}
}
src/main/resources/rules新建规则文件
package com.sample
import com.sample.DroolsTest.Message;
rule "Hello World"
when
m : Message( status == Message.HELLO, myMessage : message )
then
System.out.println( myMessage );
m.setMessage( "Goodbye cruel world" );
m.setStatus( Message.GOODBYE );
update( m );
end
rule "GoodBye"
when
Message( status == Message.GOODBYE, myMessage : message )
then
System.out.println( myMessage );
end
src/main/resources/META-INF新建配置文件kmodule.xml:
点击run可以看到结果:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Hello World
Goodbye cruel world
main函数先写一个类型为Message.HELLO类型的消息到对象中,规则文件中规定如果类型为Message.HELLO则打印出消息并且更新对象类型Message.GOODBYE,
因为update(m)这时候规则引擎将会被再次触发,因为类型更新为Message.GOODBYE将会触发规则2,打印出新类型的消息。
怎么样在Maven中使用Drools:
drools在maven中央仓库中就有,所以不需要配置额外的maven仓库,配置如下:
org.drools
drools-bom
pom
...
import
...
org.kie
kie-api
org.drools
drools-compiler
runtime
...
运行时:
这里说的运行时是指:如果你部署二进制形式的规则(KnowledgePackage对象或者KnowledgeBase对象),这样可以让你的运行时非常轻量化。可以用drools-compiler来生成规则包然后把它们部署到运行时环境。运行时环境只需要drool-core.jar和knowledge-api.jar来运行。
Rule Workbench(规则工作台)
需要Eclipse3.4以上(GEF插件3.4以上)
要不然就是用JBoss的IDE,集成好了。
通过http://www.jboss.org/drools/downloads.html 链接找到对应的Drools plug-in安装地址。
Drools运行时:
这里的运行时表示的是jar包集合,其实就是下载的不同版本的Drools。Eclipse需要一个默认的的Drools运行时。
从源代码构建Drools:
Drools和jBPM使用Git来做版本控制。链接为:https://github.com/droolsjbpm
比如guvnor子项目,build方法如下:
$ git clone [email protected]:droolsjbpm/guvnor.git ... $ cd guvnor $ mvn clean install -DskipTests -Dfull ...从6.0开始KIE,Drools(包括工作台),jBPM(包括设计器和控制台),OptaPlanner将共享相同的版本号。
KIE是什么?
KIE是一个被Drools和jBPM共享的底层库,它提供一个统一的基本方法、编程模型来构建,部署且提供了工具集。
KIE的结构:
OptaPlanner是一个本地搜索和优化工具,它现在是一个和Drools和jBPM同样的顶级项目。
Dashboard Builder是一个强大的报表工具。它独立于Drools和jBPM。
UberFire是工作台项目的基础组件,他提供了类似Eclipse样式的工作台能力(比如插件)。它也是独立于Drools和jBPM。
Guvnor在5.0里面承担了太多的职责。在6.0里面它将专注于封装UberFire插件用户构建web的IDE。
Drools和jBPM工作台的发行版本使用UberFire作为基础然后加上一些插件Guvnor以及Drools、jBPM自己的插件像decision table,guided editor,BPMN2 designer,human task。
KIE的生命周期
编辑
用可视化工具例如DRL BPMN2,decision table, class models等 编辑知识库(knowledge)
构建
把上一步编辑的知识库构建为部署单元,对于KIE这个部署单元就是jar。
测试
把jar部署到应用前请测试
部署
把jar部署到一个应用可以使用的位置
KIE使用maven风格的仓库
使用(Utilize)
加载jar然后提供一个KieSession对象,这样应用就可以和它交互了。
运行
系统通过KieSession的API和它交互
工作
用户通过UI或者命令行调用到它
管理
管理所有的KIESession或者KIEContainer
构建,部署,使用和运行
6.0引入了一个新配合和方法来build知识库,而5.0是用编程的方式,当然这个编程的方式为了向后兼容还是可用的。
KIE项目或者模块其实就是一个Maven的项目或者模块,仅仅在META-INF目录下面多了一个kmodule.xml。这个文件是用来描述选择那些知识库和配置知识库的session。它可以通过spring或者OSGI BluePrints来提供xml支持。
虽然maven可以构建和部署KIE项目,但有个插件,它会生成很多类文件,可以提供校验功能并且运行速度会更快。
示例图:
org.kie.api.core.builder内容
KieContainer
Example 4.2. 创建KieContainer
KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieService
kmodule.xml是用来声明KieBase和KIESession定义的地方。
KieBase包括rules,processes,functions和 type models。
KieBase中不包含数据
从KieBase中创建的KieSession则包含数据,KieBase的创建是重量级的东西,而KIESession是轻量级的东西。
KieContainer有机制会自动缓存住KieBase,最终用户不用担心这个问题
KieBase
KieSession也可以直接从kmodule.xml中定义的KieContainer中直接创建。
Example 4.3. kmodule.xml中配置KieBase示例
Table 4.1. kbase 属性
Attribute name | Default value | Admitted values | Meaning |
---|---|---|---|
name | none | any | The name with which retrieve this KieBase from the KieContainer. This is the only mandatory attribute. |
includes | none | any comma separated list | A comma separated list of other KieBases contained in this kmodule. The artifacts of all these KieBases will be also included in this one. |
packages | all | any comma separated list | By default all the Drools artifacts under the resources folder, at any level, are included into the KieBase. This attribute allows to limit the artifacts that will be compiled in this KieBase to only the ones belonging to the list of packages. |
default | false | true, false | Defines if this KieBase is the default one for this module, so it can be created from the KieContainer without passing any name to it. There can be at most one default KieBase in each module. |
equalsBehavior | identity | identity, equality | Defines the behavior of Drools when a new fact is inserted into the Working Memory. With identity it always create a new FactHandle unless the same object isn't already present in the Working Memory, while with equality only if the newly inserted object is not equal (according to its equal method) to an already existing fact. |
eventProcessingMode | cloud | cloud, stream | When compiled in cloud mode the KieBase treats events as normal facts, while in stream mode allow temporal reasoning on them. |
declarativeAgenda | disabled | disabled, enabled | Defines if the Declarative Agenda is enabled or not. |
Example 4.4. 从KieContainer中解析出KieBases 和 KieSessions
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 是不同的类型,一个是stateful,一个是stateless。所以他们使用的方法是不同的,如果用错了会抛出RunTimeException。
使用Maven来构建
KIE插件使得artifact会被校验和预编译,所以建议一直使用这个插件。如下图
Example 4.7. 在pom.xml中增加KIE plugin
<build>
<plugins>
<plugin>
<groupId>org.kiegroupId>
<artifactId>kie-maven-pluginartifactId>
<version>${project.version}version>
<extensions>trueextensions>
plugin>
plugins>
build>
用程序来定义KieModule
其实也可以用程序来定义KieModule里面的KieBase和KieSession。要做到这一点需要先创建一个KieFileSystem。它是一个虚拟的文件系统,然后把项目中的所有资源添加进去。
像其他的核心组件一样,你也可以从KieServices中获取KieFileSystem。
Example 4.8. 用编程方式达到 kmodule.xml 同样效果的例子
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();
下面还要给KieFileSystem加上其他必须的artifacts:
Example 4.9. Adding Kie artifacts to a KieFileSystem
KieFileSystem kfs = ...
kfs.write( "src/main/resources/KBase1/ruleSet1.drl", stringContainingAValidDRL )
.write( "src/main/resources/dtable.xls",
kieServices.getResources().newInputStreamResource( dtableFileStream ) );
KieResources
Resources的类型可以通过扩展名来推断,也可以通过ResourceType来指定,如下:
Example 4.10. Creating and adding a Resource with an explicit type
KieFileSystem kfs = ...
kfs.write( "src/main/resources/myDrl.txt",
kieServices.getResources().newInputStreamResource( drlStream )
.setResourceType(ResourceType.DRL) );
将所有资源都加载到KieFileSystem,然后把KieFileSystem传递给KieBuilder来构建。
KieBuilder
当KieFileSystem里面的内容被构建好了之后,运行结果KieModule会自动被加入KieRepository,KieRepository是一个单例。
也可以在这之后用ReleaseId通过KieServices来获得KieContainer。例如:
Example 4.11. Building the contents of a KieFileSystem and creating a KieContainer
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = ...
kieServices.newKieBuilder( kfs ).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
在这时候就可以获得KieBase和创建KieSession了,跟之前的方法类似。
最佳实践显示,最好是检查一下KieBuilder的编译结果。
Example 4.12. Checking that a compilation didn't produce any error
KieBuilder kieBuilder = kieServices.newKieBuilder( kfs ).buildAll();
assertEquals( 0, kieBuilder.getResults().getMessages( Message.Level.ERROR ).size() );
默认情况当有一个新的同名规则被加入的时候,它会替代老的规则,并打印INFO日志。大部分情况是OK的,但是有些用户想阻止这种行为并报ERROR日志。例子如下:
Example 4.13. Setting the severity using properties
// sets the severity of rule updates
drools.kbuilder.severity.duplicateRule =
// sets the severity of function updates
drools.kbuilder.severity.duplicateFunction =
4.2.3 部署
4.2.3.1 KieBase
KieBase是一个应用的知识定义集合的仓库。它包含Rules,processes,functions和type models。KieBase本身不包含任何数据。由KieBase创建的Session可以用来插入数据,然后用Session来启动进程实例。KieBase可以从KieContainer(包含了KieModule)中取到。
有时候,在OSGI环境中,KieBase需要解析不在默认类加载器中定义的类型。这时候就需要KieBaseConfiguration,它有一个额外的类加载器,当KieContainer创建KieBase的时候可以传递给它。
Example 4.14. Creating a new KieBase with a custom ClassLoader
KieServices kieServices = KieServices.Factory.get();
KieBaseConfiguration kbaseConf = kieServices.newKieBaseConfiguration( null, MyType.class.getClassLoader() );
KieBase kbase = kieContainer.newKieBase( kbaseConf );
4.2.3.2 KieSession和 KieBase修改
KieSession会在“运行”章节详细讨论。KieBase创建了KieSession对象并且保持了引用。当修改KieBase的时候这些改动也会被应用到KieSession中。这个引用默认是一个Java弱引用。当然有一个可选的boolean参数可以控制这个引用。
4.2.3.3 KieScanner
KieScanner 可以持续监控你的Maven Repository(不同于普通的maven)看看有没有一个新的Kie项目被安装。一个包含这个Kie项目的新的发布版本会被发布KieContainer中。KieScanner需要依赖kie-ci.jar包。
下面的例子显示KieScanner怎么注册到KieContainer的:
Example 4.15. Registering and starting a KieScanner on a KieContainer
KieServices kieServices = KieServices.Factory.get();
ReleaseId releaseId = kieServices.newReleaseId( "org.acme", "myartifact", "1.0-SNAPSHOT" );
KieContainer kContainer = kieServices.newKieContainer( releaseId );
KieScanner kScanner = kieServices.newKieScanner( kContainer );
// Start the KieScanner polling the Maven repository every 10 seconds
kScanner.start( 10000L );
KieScanner只会选择SNAPSHOT,版本范围,或者LATEST设置中的修改。运行时指定了版本号,则不会被更新。
4.2.3.4 Maven的版本号和依赖
Maven有一些机制可以来管理版本号和应用。应用可以指定版本发布。或则使用SNAPSHOT发布。可以通过提供特定范围的版本号或者使用SNAPSHOT机制。
StackOverFlow网站提供了一个非常好的解释:
http://stackoverflow.com/questions/30571/how-do-i-tell-maven-to-use-the-latest-version-of-a-dependency
如果你总是要使用最新版本,Maven有两个重点可以用而不用使用版本范围这个方法。你需要小心使用这些参数因为你已经不再控制这些插件和依赖关系。
当你依赖一个插件或者依赖,你可以再version字段使用LATEST或者RELEASE。LATEST表示最新的发布版本或者SNAPSHOT版本。RELEASE表示最新的RELEASE版本,不包含SNAPSHOT版本。总而言之,最好不要不设定具体的版本。废话省略。
详情请看Maven的POM的语法描述:
http://books.sonatype.com/mvnref-book/reference/pom-relationships-sect-pom-syntax.html
http://books.sonatype.com/mvnref-book/reference/pom-relationships-sect-project-dependencies.html
下面是一个例子:
<metadata>
<groupId>com.foogroupId>
<artifactId>my-fooartifactId>
<version>2.0.0version>
<versioning>
<release>1.1.1release>
<versions>
<version>1.0version>
<version>1.0.1version>
<version>1.1version>
<version>1.1.1version>
<version>2.0.0version>
versions>
<lastUpdated>20090722140000lastUpdated>
versioning>
metadata>
[1.0.1]
显示申明一个版本(除非版本冲突,否则总是这个版本):
1.0.1
(废话不详说)
4.2.3.5 Settings.xml和远程仓库安装:
(废话不详说)
4.2.4 运行
4.2.4.1 KieBase
KieBase是应用知识库。它包含规则,processes,函数,和类型模型。KieBase本身不包含任何数据。从KieBase中创建的session可以被插入数据,可以从session中创建processes。当KieBase定义的时候,KieBase可以从KieContainer中包含的KieModels中获取。
Example 4.16. Getting a KieBase from a KieContainer
KieBase kBase = kContainer.getKieBase();
KieSession保存和执行运行时数据。它是从KieBase中创建。
4.2.4.3 Kie运行时
kie运行时给Rules,processes提供全局设置、注册channel等方法。
4.2.4.3.1.1 Globals(全局对象)
规则引擎可以看到Globals命名对象。但是改变Globals里面的值不会重算Rules。Globals再提供静态信息方面很有效。比如在规则的RHS中提供服务。或者接收从规则引擎返回的平均值。当你在LHS中使用Globals的时候,保证它不可变,或者至少改变不会影响规则的行为。
global应该如下定义:
global java.util.List list
废话省略
4.2.4.4 事件模型
event包提供了规则引擎的事件,比如规则被触发或者对象被断言。这样就可以从应用的主流程中分离日志或者监听事件。
KieRuntimeEventManager
RuleRuntimeEventManager
待续......