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.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.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和- KieSession
- ClasspathKieProject: 它实现了- 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();
    }
}