本文不涉及Drools
的原理和介绍, 仅通过简单例子演示怎么使用Drools
.
另外, 各版本的文档可查看官方资料
Drools
也提供了一个bom
文件进行相关的包管理, 在maven项目中, pom
文件可以这样写:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-bom</artifactId>
<type>pom</type>
<version>...</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<scope>runtime</scope>
</dependency>
<dependencies>
项目的目录结构是下面这样子的
src
|--com.test.drools
| |--DroolsTest.java
resources
|--META-INF
| |--kmodule.xml
|--rules
| |--test.drl
Drools
默认会加载classpath
路径下的META-INF/kmodule.xml
文件(稍后详述)resources
下面的rules/test.drl
是规则文件, 也支持Excel
即xsl
文件下面是一个简单的例子
DroolsTest.java
内容如下:
public class DroolsTest {
public static void main(String[] args) {
// 获取 drools 实现的 KieServices 实例
KieServices kieServices = KieServices.Factory.get();
// kieServices 默认加载 classpath:META-INF/kmodule.xml 得到 KieContainer
KieContainer kContainer = kieServices.getKieClasspathContainer();
// 通过 kContainer 获取 kmodule.xml 中定义的 ksession
KieSession kieSession = kContainer.newKieSession("ksession-rules");
// 向 workingMemory 中加入一个对象
kieSession.insert("Tom");
// 通知规则引擎执行规则
kieSession.fireAllRules();
}
}
META-INF/kmodule.xml
内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
<kbase name="kbase-rules" packages="rules">
<ksession name="ksession-rules"/>
</kbase>
<kbase name="kbase-process" packages="process"> <!-- 这个没用到 -->
<ksession name="ksession-process"/>
</kbase>
</kmodule>
rules/test.drl
内容如下:
package com.test.drools
rule "hello"
when
$name:String()
then
System.out.println("hello " + $name);
end
这个例子运行的结果为在控制台输入:hello Tom
这个kmodule.xml
的文件的定义非常简单, 下面解释下里面的内容
kmodule
: 里面可以包含多个kbase
, 例子中只包含了2个kbase
: 有个name
属性, 全局不能重名; packages
指定规则所在的包,对应resources
下面的文件夹名. 多个包可以用逗号分开;kbase
下面可以有多个ksession
子节点ksession
: 有个name
属性, 全局不能重名kbase
和ksession
还有其他属性, 不太常用文件体现了kmodule
, kbase
和ksession
的定义和从上到下的包含关系. 项目会根据kmodule.xml
的定义将其解析成KieModuleModel
, KieBaseModel
, KieSessionModel
对象, 在运行时KieContainer
会根据XXModel
来创建KieModule
, KieBase
, KieSession
对象, 其中KieModule
和KieBase
只会创建一次, 而KieSession
则有可能创建多次, 因为KieSession
的创建成本很低, 同时KieSession
包含了运行时的数据, 所以可以销毁、创建若干次.
我们可以通过kmodule.xml
文件来定义KieModule
, 项目会自动解析classpath
下面的所有META-INF/kmodule.xml
文件,然后解析成KieModule
对象供Drools
引擎使用; 我们也可以不定义kmodule.xml
, 直接通过编码的方式来创建KieModule
等对象, 后面将会介绍.
我们发现在Drools
中经常接触到KIE
, 这个KIE
是JBoss
里面一些相关项目的统称, 可以理解为, JBoss
有很多项目, 使用方式比较统一, 都可以通过KIE API
来使用. 这些通用的API一般都会使用Kie
作为前缀, 比如KieServices
, KieContainer
, KieSession
等这些类都是KIE的公共API.
比较熟悉的JBoss
项目jBPM
和Drools
等, 通过KIE
统一了他们的使用方式, 在Drools
中这么用, 在jBPM
也这么用. 下面是来自官网的一张关于KIE的图:
KIE API有一些常用的类, 比如上例中, 我们通过KieServices
对象得到一个KieContainer
, 然后KieContainer
根据session name
来新建一个KieSession
, 最后通过KieSession
来运行规则
KieSession
: 该接口提供了很多方法, 可以通过这些方法访问KIE关于构建和运行的相关对象, 比如可以获取KieContainer
, 利用KieContainer
来访问KBase
和KSession
等信息; 可以获取KieRepository
对象, 利用KieRepository
来管理KieModule
等. KieServices
就是一个中心, 通过它来获取的各种对象来完成规则构建、管理和执行等操作KieContainer
: 就是一个KieBase
的容器KieBase
: 一个知识仓库, 包含了若干的规则、流程、方法等, 在Drools
中主要就是规则和方法, KieBase
不包含运行时的数据, 如果需要执行规则KieBase
中的规则, 就需要根据KieBase
创建KieSession
. 一般创建KieBase
成本较高, 只会创建一次KieSession
: 一个跟Drools
引擎交互的会话, 基于KieBase
创建, 它会包含运行时数据(事实Fact
). 我们通过KieContainer
创建KieSession
是一种较为方便的做法, 其实他本质上是从KieBase
中创建出来的KieRepository
: 一个单例对象, 它是一个存放KieModule
的仓库, KieModule
可以由kmodule.xml
文件定义KieProject
: KieContainer
通过KieProject
来创建KieModule
, 并将KieModule
放到KieRepository
中, 然后KieContainer
可以通过KieProject
来查找KieModule
定义的信息, 并根据这些信息构造KieBase
和KieSession
ClasspathKieProject
: 它实现了KieProject
接口, 它提供了根据类路径中的META-INF/kmodule.xml
文件构造KieModule
的能力, 也就是我们能够基于Maven构造Drools组件的基本保障之一另外, KIE也提供了一种策略, 能够让应用程序在运行时, 动态监测Maven
仓库中Drools
项目jar
组件的版本更新情况, 然后可以根据配置动态更新Drools
发布包, 实现热插拔功能, 这个是通过KieScanner API
实现的
前面的例子都是默认读取classpath
下的META-INF/kmodule.xml
文件的, 接下来我们通过KieFileSystem
定义KieModule
, 这样就不需要META-INF/kmodule.xml
配置文件了.
还是类似的例子, 目录结构将变为
src
|--com.test.drools
| |--KieFileSystemTest.java
resources
|--rules
| |--test.drl
其中 KKieFileSystemTest.java
内容为:
public class KieFileSystemTest {
public static void main(String[] args) {
// 获取 drools 实现的 KieServices 实例
KieServices kieServices = KieServices.Factory.get();
// 创建一个 KieFileSystem
KieFileSystem fileSystem = kieServices.newKieFileSystem();
// 创建一个 KieResources 对象
KieResources resources = kieServices.getResources();
// 1. 先创建 KieModuleModel, 类似于xml中的 kmodule 节点
KieModuleModel kieModuleModel = kieServices.newKieModuleModel();
// 2. 再创建 KieBaseModel, 类似于xml中的 kbase节点, name=kbase-rules, package=rules
KieBaseModel baseModel = kieModuleModel.newKieBaseModel("kbase-rules").addPackage("rules");
// 3. 再创建 KieSessionModel, 类似于xml中的 ksession 节点, name=ksession-rules
baseModel.newKieSessionModel("ksession-rules");
// 4. 生产一个xml文件,就是kmodule.xml文件
String xml = kieModuleModel.toXML();
System.out.println(xml); // 打印出来看看内容
// 5. 将这个xml文件写入到KieFileSystem中
fileSystem.writeKModuleXML(xml);
// 6. 然后将规则文件等写入到 KieFileSystem 中
// fileSystem.write("src/main/resources/rules/test.drl", resources.newClassPathResource("rules/test.drl"));
fileSystem.write(resources.newClassPathResource("rules/test.drl")); // 跟上面等效
// 7. 最后通过 KieBuilder 进行构建就将该 kmodule 加入到 KieRepository 中, 这样就将自定义的kmodule加入到引擎中了
KieBuilder kb = kieServices.newKieBuilder(fileSystem);
kb.buildAll(); // 编译
// 下面就可以向原来一样使用了
// 得到 KieContainer
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
// 通过 kContainer 获取 kmodule.xml 中定义的 ksession
KieSession kieSession = kieContainer.newKieSession("ksession-rules");
// 向 workingMemory 中加入一个对象
kieSession.insert("Tom");
// 通知规则引擎执行规则
kieSession.fireAllRules();
}
}