Drools简单使用示例
本文不涉及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.drlDrools默认会加载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.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等对象, 后面将会介绍.
KIE
我们发现在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和KieSessionClasspathKieProject: 它实现了KieProject接口, 它提供了根据类路径中的META-INF/kmodule.xml文件构造KieModule的能力, 也就是我们能够基于Maven构造Drools组件的基本保障之一
另外, KIE也提供了一种策略, 能够让应用程序在运行时, 动态监测Maven仓库中Drools项目jar组件的版本更新情况, 然后可以根据配置动态更新Drools发布包, 实现热插拔功能, 这个是通过KieScanner API实现的
编码方式实现kmodule定义
前面的例子都是默认读取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();
}
}