精华内容
下载资源
问答
  • Drools入门

    2017-10-17 11:38:47
    Drools入门系列(一)HelloWorldDrools入门系列(二)HelloWorld详解之Sample.drlDrools入门系列(三)HelloWorld详解之kmodule.xmlDrools入门系列(四)HelloWorld详解之JUnit Test类Drools入门系列(五)KIE概论...
    • Drools入门系列(一)HelloWorld
    • Drools入门系列(二)HelloWorld详解之Sample.drl
    • Drools入门系列(三)HelloWorld详解之kmodule.xml
    • Drools入门系列(四)HelloWorld详解之JUnit Test类
    • Drools入门系列(五)KIE概论
    • Drools入门系列(六)KIE之基础API详解
    • Drools入门系列(七)KIE之kmodule.xml
    • Drools入门系列(八)以编码方式完成kmodule的定义

    Drools入门系列(一)HelloWorld

    1、什么是Drools

    Drools是用Java语言编写的开放源码的规则引擎。

    那什么是规则引擎呢?参考自 百度百科 里面的定义:

    规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。

    Drools使用RETE算法对规则进行求值,在Drools6.0(当前最新版本)中还引进了PHREAK算法,Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。Drools 还具有其他优点:

    • 非常活跃的社区支持
    • 易用
    • 快速的执行速度
    • 在 Java 开发人员中流行
    • 与 Java Rule Engine API(JSR 94)兼容

    2、一些说明

    目前本人正在学习Drools过程中,准备编写一个系列文章,来记录自己的学习过程和学习心得。由于本人目前也是新手,因而文章中不可避免有着一些错误的理解,这个只有希望读者自己来判断了。

    本系列文章基于当前最新版本Drools 6.0.1 Final版本。

    在学习Drools的过程中,我也会编写一些学习的例子,这些例子都放在GitHub上:

    https://github.com/XiongZhijun/nut-drools.git

    然后我会通过一些tag来标记一些例子,读者可以自己checkout相应的tag来查看例子,一般这些tag都会有相应的注释的。

    Git入门学习可以参考:Git入门资料

    3、Hello World

    从GitHub上下载nut-drools工程(使用上节里面的地址),checkout training_1标签,就可以看到HelloWorld的例子。工程结构如下: 
    工程结构图

    drools-helloworld-project 
    这是一个典型的Maven工程,包含pom.xml文件,有src/main/java、src/main/resources,以及相应的测试目录。其中:

    src/main/resources/META-INF :该目录中存放了一个kmodule.xml文件,该文件中声明了若干已经定义了的规则、流程文件。 
    src/main/resources :该目录的子目录dtables和rules中存放了定义了规则的规则文件,本例中包含了两种定义规则的方式,一种是通过DRL(后缀.drl)文件来定义的,一种是通过Excel文件(后缀.xls)来定义的。 
    src/test/java :该目录中定义了单元测试用例,就是直接测试运行规则的。 
    现在可以直接执行单元测试,查看测试结果了。

    4、Drools and Eclipse

    Drools提供了Eclipse插件,可以在 http://www.jboss.org/drools/downloads 页面进行下载“Drools and jBPM Tools”,在这个下载包里面就包含有Eclipse插件。

    装好插件后可以使用Drools透视图,然后就可以直接创建Drools Project了: 
    1 
    new-drools-project-1 
    2 
    new-drools-project-2 
    3 
    new-drools-project-3 
    在这一步可以选择一些例子,这样在工程创建好之后就会有相应的例子程序了,上面提供的HelloWorld就是这个里面的自动创建的例子。 
    4 
    new-drools-project-4 
    输入好GroupId、AtifactId、Version后点击Finish就可以创建好一个工程了。

    大家可以注意到这个工程也是一个Maven结构的工程,除了没有pom.xml之外。不知道没有pom.xml文件这个是Drools有自己的考虑之外呢,还是这是一个bug。

    PS:drools 6.5 的时候,是可以使用Eclipse插件进行创建maven工程了。
     
    • 1

    Drools入门系列(二)——HelloWorld详解之Sample.drl

    我们来先看一下一个标准的规则文件定义文件是怎么样的:

    package os.nut.drools
    
    import os.nut.drools.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
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Java程序员可以很清楚看出来,这个规则文件跟一个Java文件非常类似,里面包含了很多Java语句,不用怀疑,这些就是Java代码,而不是类Java语法的代码。

    上面这个规则文件里面包含4个部分:package、import和两个rule:

    • package:package语句的定义跟Java里面的package语句类似,唯一不同的就是在DRL文件中package后面跟的包名是不需要跟文件目录有对应关系的,上例就可以看出来这个不同:package定义是os.nut.drools,而所在的目录是rules。

    • import:import语句的含义跟java中是一样的,就是如果在本文件中需要使用某些类的话,需要通过import语句引入进来,如果需要的类在 package定义的包中就不需要再引入了,这个跟Java的概念是一致的。在上例中的import语句其实是没有必要的。

    • rule:上例定义了两个rule,也就是定义了两个规则。一个规则以rule关键字开始,以end关键字结束。上面一个rule包含了三个部分,分别是name、when、then。

    • name紧跟在rule关键字之后,可以是一个以引号(双引号、单引号均可)包含的字符串,可以包含空格等字符,如果字符串只包含字母、数字、下划线(也就是Java变量命名规则)的话,也可以不用引号,但是推荐使用引号。

    • when语句的意思就是执行下面then语句的条件,也就是说当when条件满足的情况下,才会执行then,类似于Java里面的if语句,为什么用when而不用if呢,这是因为when代表的意思是当什么“ 事件 ”发生时,当什么“ 事实 ”存在时,然后执行then。

    • then语句就是执行的动作,就是当什么事件发生,或者什么事实存在时,执行的动作序列。then后面的语句也就是Action。

    • 事件和事实是什么东西呢?在Drools里面这两个分别称之为“Event”和“Fact”,“事件”其实也是“事实”,只不过是一种特殊的事实而已。

    • 事实是什么东西呢?一个事实其实就是一个POJO,只不过这个Java对象是存放在一个特殊的空间里面,这个空间就是“Working Memory”,所有存放在Working Memory里面的对象都是事实(Fact)。when语句就是检查在Working Memory里面是不是存在满足条件的事实。

    • 事件呢?怎么个特殊法?这个我们可以暂时不用管它,到后面学习CEP的时候自然就会理解了。CEP是什么?现在不用管它! 
      when语句解读:

    m : Message( status == Message.HELLO, myMessage : message )
    
     
    • 1
    • 2

    上面是rule “Hello World”的when语句。这个语句是什么意思呢?它的意思就是:

    当存在一个Message对象,并且这个Message的status字段值为Message.HELLO的时候,就可以执行下面的then语句了。用自然语言描述就是:当存在一个状态为HELLO的消息的事实时,就执行下面的动作,否则就不做。

    其中Message()就是执行类型匹配,意思就是要求Working Memory中存在类型为Message的对象(事实),然后status==Message.HELLO语句呢,就是约束条件,表示该Message对象的status字段为HELLO才符合条件。

    另外的m和myMessage分别表示什么呢?m加冒号的意思是将这个Message对象赋值给m,而myMessage加冒号表示将这个Message对象的message字段的值赋值给myMessage变量。然后在下面的then语句中使用这些定义的变量了。 
    then语句解读:

    System.out.println( myMessage );
    m.setMessage( "Goodbye cruel world" );
    m.setStatus( Message.GOODBYE );
    update( m );
     
    • 1
    • 2
    • 3
    • 4

    这个例子里面前三句都是普通的Java语句,唯一不同的就是下面这个update语句,这个语句的意思就是通知规则引擎m对象发生变化了,m是什么?m就是一个存放在Working Memory里面的一个Message事实,这句话就是说m这个事实发生了变化,那么规则引擎就需要重新进行规则运算,在本例中就是会在执行了update之后执行下面的“GoodBye”规则。

    为什么执行“GoodBye”规则?GoodBye规则需要匹配的是status为GOODBYE的Message事实,但是一开始并没有这样的事实存在,只有当“Hello World”规则执行到了update语句的时候,更新了Message事实,这个时候规则引擎重新运算规则,WorkingMemory中就存在status为GOODBYE的Message事实了,“GoodBye”规则就会运行了,这个从控制台输出中就可以看出来了。


    Drools入门系列(三)——HelloWorld详解之kmodule.xml

    kmodule.xml文件存放在src/main/resources/META-INF/文件夹下。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="rules" packages="rules">
            <ksession name="ksession-rules"/>
        </kbase>
        <kbase name="dtables" packages="dtables">
            <ksession name="ksession-dtables"/>
        </kbase>
    </kmodule>
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个kmodule.xml的文件的定义非常简单,其实也很容易理解:

    • 一个kmodule里面包含了两个kbase,这个也是我们这个例子里面的两个用例,分别对应drl规则文件的例子,一个是对应Excel表格的规则例子。

    • 每一个kbase都有一个name,可以取任意字符串,但是不能重名。

    • 然后都有一个packages,可以看到packages里面的字符串其实就是src/main/resources下面的文件夹的名称,或者叫包名,规则引擎会根据这里定义的包来查找规则定义文件。可以同时定义多个包,以逗号分隔开来就行。

    • 每一个kbase下面可以包含多个ksession,当然本例中都自定义了一个。

    • 每一个ksession都有一个name,名字也可以是任意字符串,但是也不能重复。

    • kbase和ksession里面的name属性是全局不能重复的。

    • kbase和ksession中其实还有很多其它的属性,但是在这里不是很重要,就先不提了,后面我们会一一讲解的。

    这样一个kmodule.xml文件就建立好了。

    看完这个大家肯定都会有疑问:kmodule、kbase、ksession是什么东东?有什么含义吗?在接下来的章节中会一一解答的,这里大家知道这样的东西,然后依葫芦画瓢就可以了,在初学过程中这样也就够了。


    Drools入门系列(四)——HelloWorld详解之JUnit Test类

    测试类 
    在本例中,有两个测试类,分别是DroolsTest和DecisionTableTest,分别对应DRL规则文件的测试和Excel表格规则的测试。两者的结果是一样的。基于Excel的方式我们先不管它,后面我会开辟专门的章节来讲述。 
    DroolsBaseTest.java

    public abstract class DroolsBaseTest {
    
        protected KieServices kieServices;
        protected KieContainer kieContainer;
    
        @Before
        public void setUp() {
            kieServices = KieServices.Factory.get();
            kieContainer = kieServices.getKieClasspathContainer();
        }
    
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这是一个抽象类,就是将一些单元测试的公共的代码抽取到了本类中,在这里定义了两个对象kieServices和kieContainer,这个是我们执行规则时必备的两个对象,这两个对象的具体意义,我们后面再讨论,这里只需要知道他们是我们执行规则必备的对象就可以了。

    DroolsTest.java

    public class DroolsTest extends DroolsBaseTest {
    
        @Test
        public void test() {
            KieSession kSession = kieContainer.newKieSession("ksession-rules");
            Message message = new Message();
            message.setMessage("Hello World");
            message.setStatus(Message.HELLO);
            kSession.insert(message);
            kSession.fireAllRules();
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这个单元测试类继承自DroolsBaseTest,演示了一个规则运行的例子。

    • 利用kieContainer对象创建一个新的KieSession,创建session的时候我们传入了一个name:“ksession-rules”,这个字符串很眼熟吧,这个就是我们定义的kmodule.xml文件中定义的ksession的name。

    • KieSession就是一个到规则引擎的链接,通过它就可以跟规则引擎通讯,并且发起执行规则的操作。

    • 然后通过kSession.fireAllRules方法来通知规则引擎执行规则。

    这样一个完整的Drools例子就完成了,包含了规则定义(DRL文件编写)、模块定义(kmodule.xml编写)、执行代码编写三个过程。


    Drools入门系列(五)——KIE概论

    1、引言

    在上一章节我们用到了几个类和他们的对象:KieServices、KieContainer、KieSession,新入门的人肯定很困惑,这几个类都是干啥的,都有什么作用啊?然后再kmodule.xml配置文件里面配置了kbase、ksession,这些东西都是什么玩意?本章以及后面可能的几章就是要解决这些问题。

    2、什么是KIE?

    KIE是jBoss里面一些相关项目的统称,下图就是KIE代表的一些项目,其中我们比较熟悉的就有jBPM和Drools。

    这些项目都有一定的关联关系,并且存在一些通用的API,比如说涉及到构建(building)、部署(deploying)和加载(loading)等方面的,这些API就都会以KIE作为前缀来表示这些是通用的API。前面看到的一些KieServices、KieContainer、KieSession类就都是KIE的公共API。

    总的来说,就是jBoss通过KIE将jBPM和Drools等相关项目进行了一个整合,统一了他们的使用方式。像KieServices这些KIE类就是整合后的结果,在Drools中这样使用,在jBPM里面也是这样使用。 
    KIE内部结构图

    3、KIE项目生命周期

    一个Drools应用项目其实就是一个KIE项目,KIE的生命周期其实就是Drools和jBPM这些项目的生命周期。

    KIE项目生命周期包含:编写(Author)、构建(Build)、测试(Test)、部署(Deploy)、使用(Utilize)、执行(Run)、交互(Work)、管理(Manage)。

    编写:编写就是编写规则文件或者流程文件; 
    构建:就是构建一个可以发布部署的组件,在KIE中就是构建一个jar文件; 
    测试:在部署到应用程序之前需要对规则或者流程进行测试; 
    部署:就是将jar部署到应用程序,KIE利用Maven仓库来进行发布和部署; 
    使用:就是加载jar文件,并通过KieContainer对jar文件进行解析,然后创建KieSession; 
    执行:系统通过KieSession对象的API跟Drools引擎进行交互,执行规则或者流程; 
    交互:用户通过命令行或者UI跟引擎进行交互; 
    管理:管理KieSession或者KieContainer对象。

    4、KIE & Maven

    通过前面的知识我们了解到Drools工程其实就是一个Maven工程,有着Maven工程标准的结构,然后Drools在这个基础上也定义了一个自己的存储结构: 
    Maven项目结构 
    drools的标准存储结构就是在src/main/resources文件夹下面存储规则文件(包括DRL文件和Excel文件),然后在META-INF文件夹下面创建一个kmodule.xml文件用来存储规则定义声明。

    Drools项目最终都是打包成jar然后进行发布部署的(KIE项目生命周期提到的),这样定义工程结构和打包发布方式的根本原因就是——Maven! 
    maven 
    上图描述了KIE项目(包括Drools)的打包、发布、部署过程,就是一个KIE项目按照上面定义的工程结构进行设计开发,然后通过mvn deploy命令发布到Maven仓库,然后应用程序可以通过mvn install将发布好的jar包下载安装到本地应用程序中,最后通过KieServices等API就可以直接使用这些发布好的规则了。

    为什么我们写的JUnit Test类里面驱动一个规则的代码非常简单,就是因为Drools定义了上面的一套规范,按照规范来编写、发布、部署规则之后就可以确保以最简单的方式来使用Drools等KIE项目。这也是惯例优于配置的一种体现。

    所以我们说一个Drools项目工程就是一个Maven项目工程,或者说一个KIE项目工程就是一个Maven工程。

    KIE也提供了一种策略,能够让应用程序在运行时,能够动态监测Maven仓库中Drools项目jar组件的版本更新情况,然后可以根据配置动态更新Drools发布包,实现热插拔功能,这个是通过KieScanner API实现的。


    Drools入门系列(六)——KIE之基础API详解

    在有些术语使用的时候,我有时候会用KIE项目、KIE引擎或者Drools项目、Drools引擎,大家应该理解KIE是Drools等项目的一个统称,所以在大多数情况下KIE或者特指Drools都是差不多的。

    现在我们开始了解KIE的相关API,在这个helloworld例子中,我们接触过如下这些类和接口: 
    基本类和接口 
    我们通过KieServices对象得到一个KieContainer,然后KieContainer根据session name来新建一个KieSession,最后通过KieSession来运行规则。

    KieServices:

    该接口提供了很多方法,可以通过这些方法访问KIE关于构建和运行的相关对象,比如说可以获取KieContainer,利用KieContainer来访问KBase和KSession等信息;可以获取KieRepository对象,利用KieRepository来管理KieModule等。

    KieServices就是一个中心,通过它来获取的各种对象来完成规则构建、管理和执行等操作。

    KieContainer:

    可以理解KieContainer就是一个KieBase的容器,KieBase是什么呢?

    KieBase:

    KieBase就是一个知识仓库,包含了若干的规则、流程、方法等,在Drools中主要就是规则和方法,KieBase本身并不包含运行时的数据之类的,如果需要执行规则KieBase中的规则的话,就需要根据KieBase创建KieSession。 
    KieSession:

    KieSession就是一个跟Drools引擎打交道的会话,其基于KieBase创建,它会包含运行时数据,包含“事实 Fact”,并对运行时数据事实进行规则运算。我们通过KieContainer创建KieSession是一种较为方便的做法,其实他本质上是从KieBase中创建出来。的。

    KieSession就是应用程序跟规则引擎进行交互的会话通道。

    创建KieBase是一个成本非常高的事情,KieBase会建立知识(规则、流程)仓库,而创建KieSession则是一个成本非常低的事情,所以KieBase会建立缓存,而KieSession则不必。

    较为完善的类关系如下: 
    详细关系 
    KieRepository:

    KieRepository是一个单例对象,它是一个存放KieModule的仓库,KieModule由kmodule.xml文件定义(当然不仅仅只是用它来定义)。

    KieProject:

    KieContainer通过KieProject来初始化、构造KieModule,并将KieModule存放到KieRepository中,然后KieContainer可以通过KieProject来查找KieModule定义的信息,并根据这些信息构造KieBase和KieSession。

    ClasspathKieProject:

    ClasspathKieProject实现了KieProject接口,它提供了根据类路径中的META-INF/kmodule.xml文件构造KieModule的能力,也就是我们能够基于Maven构造Drools组件的基本保障之一。

    意味着只要我们按照前面提到过的Maven工程结构组织我们的规则文件或流程文件,我们就能够只用很少的代码完成模型的加载和构建。 
    现在我们知道了可以通过ClasspathKieProject来解析kmodule.xml文件来构建KieModule,那么整个过程是如何进行的呢?kmodule.xml里面的kbase、ksession和KieBase和KieSession又是什么关系呢?下一章节我们继续。


    Drools入门系列(七)——KIE之kmodule.xml

    一个标准的kmodule.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="rules" packages="rules">
            <ksession name="ksession-rules"/>
        </kbase>
        <kbase name="dtables" packages="dtables">
            <ksession name="ksession-dtables"/>
        </kbase>
    </kmodule>
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上一章节我们提到了ClasspathKieProject根据kmodule.xml文件来构造KieModule对象。KieModule是什么呢?跟KieBase、KieSession之间又是什么关系呢?我们看一下: 
    KieBase KieModule KieSession 
    上图可以以关系图的方式来理解,而不是准确表示类之间的关系。

    从总的来说,左边的接口描述了一种“定义”,而右边的接口则描述的是一种运行时对象,右边的运行时对象是根据左边的定义创建出来的。

    然后我们看到很多的“包含”关系,左边的关系体现的就是在kmodule.xml文件中的kmodule、kbase和ksession的定义和从上到下的包含关系。

    在ClasspathKieProject类中,会根据kmodule.xml文件的定义,将其解析并生成成KieModuleModel、KieBaseModel、KieSessionModel对象,基于这个原理,那么我们也可以抛开kmodule.xml文件,通过编程的方式创建这些Model对象,这个在稍后的章节中会讲到。

    在运行时,KieContainer会根据*Model对象来创建KieModule、KieBase、KieSession对象。其中KieModule和KieBase只会创建一次,而KieSession则有可能创建多次,因为KieSession的创建成本很低,同时KieSession包含了运行时的数据,所以可以销毁、创建若干次。

    kmodule.xml文件中的kbase和ksession标签都有很多的属性,这些属性映射到Java对象的时候就对应着相关的对象的字段,下面我们详细了解一下有那些属性: 
    ps:懒得打字了,汗,大家别嫌弃 
    kbase的属性: 
    kbase的属性
    ksession的属性: 
    ksession的属性
    这样我们就可以通过kmodule.xml文件来定义KieModule了,ClasspathKieProject会自动解析classpath下面的所有META-INF/kmodule.xml文件,然后解析成KieModule对象供Drools引擎使用。


    Drools入门系列(八)——以编码方式完成kmodule的定义

    在Git里面checkout training_2这个例子,就会发现在多了一个KieFileSystemTest单元测试:

    public class KieFileSystemTest {
    
        @Test
        public void test() {
            KieServices kieServices = KieServices.Factory.get();
            KieResources resources = kieServices.getResources();
            KieModuleModel kieModuleModel = kieServices.newKieModuleModel();//1
    
            KieBaseModel baseModel = kieModuleModel.newKieBaseModel(
                    "FileSystemKBase").addPackage("rules");//2
            baseModel.newKieSessionModel("FileSystemKSession");//3
            KieFileSystem fileSystem = kieServices.newKieFileSystem();
    
            String xml = kieModuleModel.toXML();
            System.out.println(xml);//4
            fileSystem.writeKModuleXML(xml);//5
    
            fileSystem.write("src/main/resources/rules/rule.drl", resources
                    .newClassPathResource("kiefilesystem/KieFileSystemTest.drl"));//6
    
            KieBuilder kb = kieServices.newKieBuilder(fileSystem);
            kb.buildAll();//7
            if (kb.getResults().hasMessages(Level.ERROR)) {
                throw new RuntimeException("Build Errors:\n"
                        + kb.getResults().toString());
            }
            KieContainer kContainer = kieServices.newKieContainer(kieServices
                    .getRepository().getDefaultReleaseId());
    
            assertNotNull(kContainer.getKieBase("FileSystemKBase"));
            KieSession kSession = kContainer.newKieSession("FileSystemKSession");
    
            kSession.fireAllRules();
        }
    }
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    这个用例演示了如何利用编码的方式来构建kmodule了,整个流程很简单,就是:

    1. 先创建KieModuleModel;
    2. 再创建KieBaseModel;
    3. 然后创建 KieSessionModel;
    4. 创建完成之后可以生产一个xml文件,就是kmodule.xml文件了;
    5. 将这个xml文件写入到KieFileSystem中;
    6. 然后将规则文件等写入到KieFileSystem中;
    7. 最后通过KieBuilder进行构建就将该kmodule加入到KieRepository中了。这样就将自定义的kmodule加入到引擎中了,就可以按照之前的方法进行使用了。

    参考资料

    [1] http://www.tuicool.com/articles/3EFNV3M 
    [2] http://www.tuicool.com/articles/JV7J7zr 
    [3] http://www.tuicool.com/articles/ememuq 
    [4] http://www.tuicool.com/articles/InMjei 
    [5] http://www.tuicool.com/articles/b2yqeq 
    [6] http://www.tuicool.com/articles/jeIVjiy 
    [7]http://www.tuicool.com/articles/22au6zV 
    [8] http://www.tuicool.com/articles/qqIFvy

    展开全文
  • Drools 入门

    2021-07-31 20:23:50
    Drools 是一款基于 Java 语言的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(这里可以是数据库表),使得业务规则的变更不需要修正项目代码、重启...

    概述

    Drools 是一款基于 Java 语言的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以规则脚本的形式存放在文件或特定的存储介质中(这里可以是数据库表),使得业务规则的变更不需要修正项目代码、重启服务器就可以在线上环境立即生效。

    Drools 规则引擎是为开发人员提供的 KRR 功能程序,KRR 是人工智能的核心,所以 Drools 也是人工智能的一个分支,是专家系统的另一种展现方式。

    Hello Drools 示例

    • 步骤1:pom 引入依赖
    <dependencyManagement>
    	<dependencies>
    		<dependency>
    			<groupId>org.drools</groupId>
    			<artifactId>drools-bom</artifactId>
    			<type>pom</type>
    			<version>7.57.0.Final</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>
    	<dependency>
    		<groupId>org.drools</groupId>
    		<artifactId>drools-mvel</artifactId>
    	</dependency>
    </dependencies>
    
    • 步骤2:src/main/resouces 新建 rules/hello 目录,并新增规则文件 hello.drl
    package rules.hello 
    
    rule "test001"
    	when 
      		eval(true);
    	then 
      		System.out.println("hello drools");
    end
    
    • 步骤3:src/main/resources 新建 META-INF 目录,并新增 kmodule.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule
    	xmlns="http://www.drools.org/xsd/kmodule">
    	<kbase name="rules" packages="rules.hello">
    		<ksession name="helloDrools"/>
    	</kbase>
    </kmodule>
    
    • 步骤4:main 方法测试规则文件
    public class RulesHello {
        public static void main(String[] args) {
            KieServices kss = KieServices.Factory.get();
            KieContainer kc = kss.getKieClasspathContainer();
            KieSession ks = kc.newKieSession("helloDrools");
            int count = ks.fireAllRules();
            System.out.println("总执行了" + count + "条规则");
            ks.dispose();
        }
    }
    

    结果:运行结果

    规则文件

    规则文件内容一般包含三大块,即包路径、引用、规则体。

    规则文件名

    规则文件名即 hello.drl,不要求首字母大写。命名规范,见名知意。

    规则文件内容

    package

    关键字 package 为三大块中的包路径,是逻辑路径。在规则文件中关键字 package 永远在代码的第一行(规则模板除外)。

    import

    关键字 import 为三大块中的引用,目的是为了对象类引用。与 Java 不同的是,在引用静态方法时,需要添加 function 关键字。

    rule

    关键字 rule 为三大块中的规则体,是核心内容之一,以关键字 rule 开头,以 end 结尾,每个规则文件中可以包含多个 rule规则体,但 rule 规则体之间不能交叉使用,即一个 rule 只能对应一个 end。

    rule 的参数,即规则名,建议驼峰式命名,并为每一个规则名都加上引号,以避免出现编译报错的问题。

    同一个规则库中相同规则逻辑路径下的规则名不可以相同,可以理解为规则名即是一个 ID,不可重复。

    规则体说明

    规则体是规则文件内容中的核心,分为 LHS、RHS 两大功能模块。

    LHS

    条件部分又被称为 Left Hand Side(LHS),即规则体 when 与 then 中间的部分。在 LHS 中,可以包含 0~n 个条件,如果 LHS 部分为空,那么引擎会自动添加一个 eval(true)条件,由于该条件总是返回 true,因此 LHS 为空的规则体也总是返回 true。LHS 条件不满足,规则体就不会执行 RHS 模块。

    RHS

    结果部分又被称为 Right Hand Side(RHS),即一个规则体中 then 与 end 中间的部分,只有 LHS 部分的条件都满足时 RHS 部分才会被执行。

    Fact

    Drools 规则引擎中传递的数据,术语称 Fact 对象。

    Drools 加载规则时,会将所有规则体中的 LHS 部分先执行,区别于规则体的 RHS 部分不进行运算。只有 Fact 对象发生了改变,规则体才有可能重新被激活,之前为 false 的 LHS 有可能变成 true。

    Fact 对象是一个普通的 JavaBean,规则体中可以对当前对象进行任何的读/写操作,调用该对象提供的方法。当一个 Fact 插入 Working Memory(内存储存)中,规则体使用的是原有对象的引用(并不是克隆,与 Java 变量性质相似),规则体通过操作 Fact 对象来实现对应用数据的管理,对于其中的属性,需要提供 getter/setter 方法。执行规则时,可以动态地向当前 Working Memory插入、删除或更新 Fact 对象。

    展开全文
  • Drools入门系列

    千次阅读 多人点赞 2016-12-14 00:30:12
    Drools入门系列(一)HelloWorld Drools入门系列(二)HelloWorld详解之Sample.drl Drools入门系列(三)HelloWorld详解之kmodule.xml Drools入门系列(四)HelloWorld详解之JUnit Test类 Drools入门系列(五)KIE...
    • Drools入门系列(一)HelloWorld
    • Drools入门系列(二)HelloWorld详解之Sample.drl
    • Drools入门系列(三)HelloWorld详解之kmodule.xml
    • Drools入门系列(四)HelloWorld详解之JUnit Test类
    • Drools入门系列(五)KIE概论
    • Drools入门系列(六)KIE之基础API详解
    • Drools入门系列(七)KIE之kmodule.xml
    • Drools入门系列(八)以编码方式完成kmodule的定义

    Drools入门系列(一)HelloWorld

    1、什么是Drools

    Drools是用Java语言编写的开放源码的规则引擎。

    那什么是规则引擎呢?参考自 百度百科 里面的定义:

    规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。

    Drools使用RETE算法对规则进行求值,在Drools6.0(当前最新版本)中还引进了PHREAK算法,Drools 允许使用声明方式表达业务逻辑。可以使用非 XML 的本地语言编写规则,从而便于学习和理解。并且,还可以将 Java 代码直接嵌入到规则文件中,这令 Drools 的学习更加吸引人。Drools 还具有其他优点:

    • 非常活跃的社区支持
    • 易用
    • 快速的执行速度
    • 在 Java 开发人员中流行
    • 与 Java Rule Engine API(JSR 94)兼容

    2、一些说明

    目前本人正在学习Drools过程中,准备编写一个系列文章,来记录自己的学习过程和学习心得。由于本人目前也是新手,因而文章中不可避免有着一些错误的理解,这个只有希望读者自己来判断了。

    本系列文章基于当前最新版本Drools 6.0.1 Final版本。

    在学习Drools的过程中,我也会编写一些学习的例子,这些例子都放在GitHub上:

    https://github.com/XiongZhijun/nut-drools.git

    然后我会通过一些tag来标记一些例子,读者可以自己checkout相应的tag来查看例子,一般这些tag都会有相应的注释的。

    Git入门学习可以参考:Git入门资料

    3、Hello World

    从GitHub上下载nut-drools工程(使用上节里面的地址),checkout training_1标签,就可以看到HelloWorld的例子。工程结构如下:
    工程结构图

    drools-helloworld-project
    这是一个典型的Maven工程,包含pom.xml文件,有src/main/java、src/main/resources,以及相应的测试目录。其中:

    src/main/resources/META-INF :该目录中存放了一个kmodule.xml文件,该文件中声明了若干已经定义了的规则、流程文件。
    src/main/resources :该目录的子目录dtables和rules中存放了定义了规则的规则文件,本例中包含了两种定义规则的方式,一种是通过DRL(后缀.drl)文件来定义的,一种是通过Excel文件(后缀.xls)来定义的。
    src/test/java :该目录中定义了单元测试用例,就是直接测试运行规则的。
    现在可以直接执行单元测试,查看测试结果了。

    4、Drools and Eclipse

    Drools提供了Eclipse插件,可以在 http://www.jboss.org/drools/downloads 页面进行下载“Drools and jBPM Tools”,在这个下载包里面就包含有Eclipse插件。

    装好插件后可以使用Drools透视图,然后就可以直接创建Drools Project了:
    1
    new-drools-project-1
    2
    new-drools-project-2
    3
    new-drools-project-3
    在这一步可以选择一些例子,这样在工程创建好之后就会有相应的例子程序了,上面提供的HelloWorld就是这个里面的自动创建的例子。
    4
    new-drools-project-4
    输入好GroupId、AtifactId、Version后点击Finish就可以创建好一个工程了。

    大家可以注意到这个工程也是一个Maven结构的工程,除了没有pom.xml之外。不知道没有pom.xml文件这个是Drools有自己的考虑之外呢,还是这是一个bug。

    PS:drools 6.5 的时候,是可以使用Eclipse插件进行创建maven工程了。

    Drools入门系列(二)——HelloWorld详解之Sample.drl

    我们来先看一下一个标准的规则文件定义文件是怎么样的:

    package os.nut.drools
    
    import os.nut.drools.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

    Java程序员可以很清楚看出来,这个规则文件跟一个Java文件非常类似,里面包含了很多Java语句,不用怀疑,这些就是Java代码,而不是类Java语法的代码。

    上面这个规则文件里面包含4个部分:package、import和两个rule:

    • package:package语句的定义跟Java里面的package语句类似,唯一不同的就是在DRL文件中package后面跟的包名是不需要跟文件目录有对应关系的,上例就可以看出来这个不同:package定义是os.nut.drools,而所在的目录是rules。

    • import:import语句的含义跟java中是一样的,就是如果在本文件中需要使用某些类的话,需要通过import语句引入进来,如果需要的类在 package定义的包中就不需要再引入了,这个跟Java的概念是一致的。在上例中的import语句其实是没有必要的。

    • rule:上例定义了两个rule,也就是定义了两个规则。一个规则以rule关键字开始,以end关键字结束。上面一个rule包含了三个部分,分别是name、when、then。

    • name紧跟在rule关键字之后,可以是一个以引号(双引号、单引号均可)包含的字符串,可以包含空格等字符,如果字符串只包含字母、数字、下划线(也就是Java变量命名规则)的话,也可以不用引号,但是推荐使用引号。

    • when语句的意思就是执行下面then语句的条件,也就是说当when条件满足的情况下,才会执行then,类似于Java里面的if语句,为什么用when而不用if呢,这是因为when代表的意思是当什么“ 事件 ”发生时,当什么“ 事实 ”存在时,然后执行then。

    • then语句就是执行的动作,就是当什么事件发生,或者什么事实存在时,执行的动作序列。then后面的语句也就是Action。

    • 事件和事实是什么东西呢?在Drools里面这两个分别称之为“Event”和“Fact”,“事件”其实也是“事实”,只不过是一种特殊的事实而已。

    • 事实是什么东西呢?一个事实其实就是一个POJO,只不过这个Java对象是存放在一个特殊的空间里面,这个空间就是“Working Memory”,所有存放在Working Memory里面的对象都是事实(Fact)。when语句就是检查在Working Memory里面是不是存在满足条件的事实。

    • 事件呢?怎么个特殊法?这个我们可以暂时不用管它,到后面学习CEP的时候自然就会理解了。CEP是什么?现在不用管它!
      when语句解读:

    m : Message( status == Message.HELLO, myMessage : message )
    

    上面是rule “Hello World”的when语句。这个语句是什么意思呢?它的意思就是:

    当存在一个Message对象,并且这个Message的status字段值为Message.HELLO的时候,就可以执行下面的then语句了。用自然语言描述就是:当存在一个状态为HELLO的消息的事实时,就执行下面的动作,否则就不做。

    其中Message()就是执行类型匹配,意思就是要求Working Memory中存在类型为Message的对象(事实),然后status==Message.HELLO语句呢,就是约束条件,表示该Message对象的status字段为HELLO才符合条件。

    另外的m和myMessage分别表示什么呢?m加冒号的意思是将这个Message对象赋值给m,而myMessage加冒号表示将这个Message对象的message字段的值赋值给myMessage变量。然后在下面的then语句中使用这些定义的变量了。
    then语句解读:

    System.out.println( myMessage );
    m.setMessage( "Goodbye cruel world" );
    m.setStatus( Message.GOODBYE );
    update( m );

    这个例子里面前三句都是普通的Java语句,唯一不同的就是下面这个update语句,这个语句的意思就是通知规则引擎m对象发生变化了,m是什么?m就是一个存放在Working Memory里面的一个Message事实,这句话就是说m这个事实发生了变化,那么规则引擎就需要重新进行规则运算,在本例中就是会在执行了update之后执行下面的“GoodBye”规则。

    为什么执行“GoodBye”规则?GoodBye规则需要匹配的是status为GOODBYE的Message事实,但是一开始并没有这样的事实存在,只有当“Hello World”规则执行到了update语句的时候,更新了Message事实,这个时候规则引擎重新运算规则,WorkingMemory中就存在status为GOODBYE的Message事实了,“GoodBye”规则就会运行了,这个从控制台输出中就可以看出来了。


    Drools入门系列(三)——HelloWorld详解之kmodule.xml

    kmodule.xml文件存放在src/main/resources/META-INF/文件夹下。

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="rules" packages="rules">
            <ksession name="ksession-rules"/>
        </kbase>
        <kbase name="dtables" packages="dtables">
            <ksession name="ksession-dtables"/>
        </kbase>
    </kmodule>

    这个kmodule.xml的文件的定义非常简单,其实也很容易理解:

    • 一个kmodule里面包含了两个kbase,这个也是我们这个例子里面的两个用例,分别对应drl规则文件的例子,一个是对应Excel表格的规则例子。

    • 每一个kbase都有一个name,可以取任意字符串,但是不能重名。

    • 然后都有一个packages,可以看到packages里面的字符串其实就是src/main/resources下面的文件夹的名称,或者叫包名,规则引擎会根据这里定义的包来查找规则定义文件。可以同时定义多个包,以逗号分隔开来就行。

    • 每一个kbase下面可以包含多个ksession,当然本例中都自定义了一个。

    • 每一个ksession都有一个name,名字也可以是任意字符串,但是也不能重复。

    • kbase和ksession里面的name属性是全局不能重复的。

    • kbase和ksession中其实还有很多其它的属性,但是在这里不是很重要,就先不提了,后面我们会一一讲解的。

    这样一个kmodule.xml文件就建立好了。

    看完这个大家肯定都会有疑问:kmodule、kbase、ksession是什么东东?有什么含义吗?在接下来的章节中会一一解答的,这里大家知道这样的东西,然后依葫芦画瓢就可以了,在初学过程中这样也就够了。


    Drools入门系列(四)——HelloWorld详解之JUnit Test类

    测试类
    在本例中,有两个测试类,分别是DroolsTest和DecisionTableTest,分别对应DRL规则文件的测试和Excel表格规则的测试。两者的结果是一样的。基于Excel的方式我们先不管它,后面我会开辟专门的章节来讲述。
    DroolsBaseTest.java

    public abstract class DroolsBaseTest {
    
        protected KieServices kieServices;
        protected KieContainer kieContainer;
    
        @Before
        public void setUp() {
            kieServices = KieServices.Factory.get();
            kieContainer = kieServices.getKieClasspathContainer();
        }
    
    }

    这是一个抽象类,就是将一些单元测试的公共的代码抽取到了本类中,在这里定义了两个对象kieServices和kieContainer,这个是我们执行规则时必备的两个对象,这两个对象的具体意义,我们后面再讨论,这里只需要知道他们是我们执行规则必备的对象就可以了。

    DroolsTest.java

    public class DroolsTest extends DroolsBaseTest {
    
        @Test
        public void test() {
            KieSession kSession = kieContainer.newKieSession("ksession-rules");
            Message message = new Message();
            message.setMessage("Hello World");
            message.setStatus(Message.HELLO);
            kSession.insert(message);
            kSession.fireAllRules();
        }
    }

    这个单元测试类继承自DroolsBaseTest,演示了一个规则运行的例子。

    • 利用kieContainer对象创建一个新的KieSession,创建session的时候我们传入了一个name:“ksession-rules”,这个字符串很眼熟吧,这个就是我们定义的kmodule.xml文件中定义的ksession的name。

    • KieSession就是一个到规则引擎的链接,通过它就可以跟规则引擎通讯,并且发起执行规则的操作。

    • 然后通过kSession.fireAllRules方法来通知规则引擎执行规则。

    这样一个完整的Drools例子就完成了,包含了规则定义(DRL文件编写)、模块定义(kmodule.xml编写)、执行代码编写三个过程。


    Drools入门系列(五)——KIE概论

    1、引言

    在上一章节我们用到了几个类和他们的对象:KieServices、KieContainer、KieSession,新入门的人肯定很困惑,这几个类都是干啥的,都有什么作用啊?然后再kmodule.xml配置文件里面配置了kbase、ksession,这些东西都是什么玩意?本章以及后面可能的几章就是要解决这些问题。

    2、什么是KIE?

    KIE是jBoss里面一些相关项目的统称,下图就是KIE代表的一些项目,其中我们比较熟悉的就有jBPM和Drools。

    这些项目都有一定的关联关系,并且存在一些通用的API,比如说涉及到构建(building)、部署(deploying)和加载(loading)等方面的,这些API就都会以KIE作为前缀来表示这些是通用的API。前面看到的一些KieServices、KieContainer、KieSession类就都是KIE的公共API。

    总的来说,就是jBoss通过KIE将jBPM和Drools等相关项目进行了一个整合,统一了他们的使用方式。像KieServices这些KIE类就是整合后的结果,在Drools中这样使用,在jBPM里面也是这样使用。
    KIE内部结构图

    3、KIE项目生命周期

    一个Drools应用项目其实就是一个KIE项目,KIE的生命周期其实就是Drools和jBPM这些项目的生命周期。

    KIE项目生命周期包含:编写(Author)、构建(Build)、测试(Test)、部署(Deploy)、使用(Utilize)、执行(Run)、交互(Work)、管理(Manage)。

    编写:编写就是编写规则文件或者流程文件;
    构建:就是构建一个可以发布部署的组件,在KIE中就是构建一个jar文件;
    测试:在部署到应用程序之前需要对规则或者流程进行测试;
    部署:就是将jar部署到应用程序,KIE利用Maven仓库来进行发布和部署;
    使用:就是加载jar文件,并通过KieContainer对jar文件进行解析,然后创建KieSession;
    执行:系统通过KieSession对象的API跟Drools引擎进行交互,执行规则或者流程;
    交互:用户通过命令行或者UI跟引擎进行交互;
    管理:管理KieSession或者KieContainer对象。

    4、KIE & Maven

    通过前面的知识我们了解到Drools工程其实就是一个Maven工程,有着Maven工程标准的结构,然后Drools在这个基础上也定义了一个自己的存储结构:
    Maven项目结构
    drools的标准存储结构就是在src/main/resources文件夹下面存储规则文件(包括DRL文件和Excel文件),然后在META-INF文件夹下面创建一个kmodule.xml文件用来存储规则定义声明。

    Drools项目最终都是打包成jar然后进行发布部署的(KIE项目生命周期提到的),这样定义工程结构和打包发布方式的根本原因就是——Maven!
    maven
    上图描述了KIE项目(包括Drools)的打包、发布、部署过程,就是一个KIE项目按照上面定义的工程结构进行设计开发,然后通过mvn deploy命令发布到Maven仓库,然后应用程序可以通过mvn install将发布好的jar包下载安装到本地应用程序中,最后通过KieServices等API就可以直接使用这些发布好的规则了。

    为什么我们写的JUnit Test类里面驱动一个规则的代码非常简单,就是因为Drools定义了上面的一套规范,按照规范来编写、发布、部署规则之后就可以确保以最简单的方式来使用Drools等KIE项目。这也是惯例优于配置的一种体现。

    所以我们说一个Drools项目工程就是一个Maven项目工程,或者说一个KIE项目工程就是一个Maven工程。

    KIE也提供了一种策略,能够让应用程序在运行时,能够动态监测Maven仓库中Drools项目jar组件的版本更新情况,然后可以根据配置动态更新Drools发布包,实现热插拔功能,这个是通过KieScanner API实现的。


    Drools入门系列(六)——KIE之基础API详解

    在有些术语使用的时候,我有时候会用KIE项目、KIE引擎或者Drools项目、Drools引擎,大家应该理解KIE是Drools等项目的一个统称,所以在大多数情况下KIE或者特指Drools都是差不多的。

    现在我们开始了解KIE的相关API,在这个helloworld例子中,我们接触过如下这些类和接口:
    基本类和接口
    我们通过KieServices对象得到一个KieContainer,然后KieContainer根据session name来新建一个KieSession,最后通过KieSession来运行规则。

    KieServices:

    该接口提供了很多方法,可以通过这些方法访问KIE关于构建和运行的相关对象,比如说可以获取KieContainer,利用KieContainer来访问KBase和KSession等信息;可以获取KieRepository对象,利用KieRepository来管理KieModule等。

    KieServices就是一个中心,通过它来获取的各种对象来完成规则构建、管理和执行等操作。

    KieContainer:

    可以理解KieContainer就是一个KieBase的容器,KieBase是什么呢?

    KieBase:

    KieBase就是一个知识仓库,包含了若干的规则、流程、方法等,在Drools中主要就是规则和方法,KieBase本身并不包含运行时的数据之类的,如果需要执行规则KieBase中的规则的话,就需要根据KieBase创建KieSession。
    KieSession:

    KieSession就是一个跟Drools引擎打交道的会话,其基于KieBase创建,它会包含运行时数据,包含“事实 Fact”,并对运行时数据事实进行规则运算。我们通过KieContainer创建KieSession是一种较为方便的做法,其实他本质上是从KieBase中创建出来。的。

    KieSession就是应用程序跟规则引擎进行交互的会话通道。

    创建KieBase是一个成本非常高的事情,KieBase会建立知识(规则、流程)仓库,而创建KieSession则是一个成本非常低的事情,所以KieBase会建立缓存,而KieSession则不必。

    较为完善的类关系如下:
    详细关系
    KieRepository:

    KieRepository是一个单例对象,它是一个存放KieModule的仓库,KieModule由kmodule.xml文件定义(当然不仅仅只是用它来定义)。

    KieProject:

    KieContainer通过KieProject来初始化、构造KieModule,并将KieModule存放到KieRepository中,然后KieContainer可以通过KieProject来查找KieModule定义的信息,并根据这些信息构造KieBase和KieSession。

    ClasspathKieProject:

    ClasspathKieProject实现了KieProject接口,它提供了根据类路径中的META-INF/kmodule.xml文件构造KieModule的能力,也就是我们能够基于Maven构造Drools组件的基本保障之一。

    意味着只要我们按照前面提到过的Maven工程结构组织我们的规则文件或流程文件,我们就能够只用很少的代码完成模型的加载和构建。
    现在我们知道了可以通过ClasspathKieProject来解析kmodule.xml文件来构建KieModule,那么整个过程是如何进行的呢?kmodule.xml里面的kbase、ksession和KieBase和KieSession又是什么关系呢?下一章节我们继续。


    Drools入门系列(七)——KIE之kmodule.xml

    一个标准的kmodule.xml文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">
        <kbase name="rules" packages="rules">
            <ksession name="ksession-rules"/>
        </kbase>
        <kbase name="dtables" packages="dtables">
            <ksession name="ksession-dtables"/>
        </kbase>
    </kmodule>

    上一章节我们提到了ClasspathKieProject根据kmodule.xml文件来构造KieModule对象。KieModule是什么呢?跟KieBase、KieSession之间又是什么关系呢?我们看一下:
    KieBase KieModule KieSession
    上图可以以关系图的方式来理解,而不是准确表示类之间的关系。

    从总的来说,左边的接口描述了一种“定义”,而右边的接口则描述的是一种运行时对象,右边的运行时对象是根据左边的定义创建出来的。

    然后我们看到很多的“包含”关系,左边的关系体现的就是在kmodule.xml文件中的kmodule、kbase和ksession的定义和从上到下的包含关系。

    在ClasspathKieProject类中,会根据kmodule.xml文件的定义,将其解析并生成成KieModuleModel、KieBaseModel、KieSessionModel对象,基于这个原理,那么我们也可以抛开kmodule.xml文件,通过编程的方式创建这些Model对象,这个在稍后的章节中会讲到。

    在运行时,KieContainer会根据*Model对象来创建KieModule、KieBase、KieSession对象。其中KieModule和KieBase只会创建一次,而KieSession则有可能创建多次,因为KieSession的创建成本很低,同时KieSession包含了运行时的数据,所以可以销毁、创建若干次。

    kmodule.xml文件中的kbase和ksession标签都有很多的属性,这些属性映射到Java对象的时候就对应着相关的对象的字段,下面我们详细了解一下有那些属性:
    ps:懒得打字了,汗,大家别嫌弃
    kbase的属性:
    kbase的属性
    ksession的属性:
    ksession的属性
    这样我们就可以通过kmodule.xml文件来定义KieModule了,ClasspathKieProject会自动解析classpath下面的所有META-INF/kmodule.xml文件,然后解析成KieModule对象供Drools引擎使用。


    Drools入门系列(八)——以编码方式完成kmodule的定义

    在Git里面checkout training_2这个例子,就会发现在多了一个KieFileSystemTest单元测试:

    public class KieFileSystemTest {
    
        @Test
        public void test() {
            KieServices kieServices = KieServices.Factory.get();
            KieResources resources = kieServices.getResources();
            KieModuleModel kieModuleModel = kieServices.newKieModuleModel();//1
    
            KieBaseModel baseModel = kieModuleModel.newKieBaseModel(
                    "FileSystemKBase").addPackage("rules");//2
            baseModel.newKieSessionModel("FileSystemKSession");//3
            KieFileSystem fileSystem = kieServices.newKieFileSystem();
    
            String xml = kieModuleModel.toXML();
            System.out.println(xml);//4
            fileSystem.writeKModuleXML(xml);//5
    
            fileSystem.write("src/main/resources/rules/rule.drl", resources
                    .newClassPathResource("kiefilesystem/KieFileSystemTest.drl"));//6
    
            KieBuilder kb = kieServices.newKieBuilder(fileSystem);
            kb.buildAll();//7
            if (kb.getResults().hasMessages(Level.ERROR)) {
                throw new RuntimeException("Build Errors:\n"
                        + kb.getResults().toString());
            }
            KieContainer kContainer = kieServices.newKieContainer(kieServices
                    .getRepository().getDefaultReleaseId());
    
            assertNotNull(kContainer.getKieBase("FileSystemKBase"));
            KieSession kSession = kContainer.newKieSession("FileSystemKSession");
    
            kSession.fireAllRules();
        }
    }

    这个用例演示了如何利用编码的方式来构建kmodule了,整个流程很简单,就是:

    1. 先创建KieModuleModel;
    2. 再创建KieBaseModel;
    3. 然后创建 KieSessionModel;
    4. 创建完成之后可以生产一个xml文件,就是kmodule.xml文件了;
    5. 将这个xml文件写入到KieFileSystem中;
    6. 然后将规则文件等写入到KieFileSystem中;
    7. 最后通过KieBuilder进行构建就将该kmodule加入到KieRepository中了。这样就将自定义的kmodule加入到引擎中了,就可以按照之前的方法进行使用了。

    参考资料

    [1] http://www.tuicool.com/articles/3EFNV3M
    [2] http://www.tuicool.com/articles/JV7J7zr
    [3] http://www.tuicool.com/articles/ememuq
    [4] http://www.tuicool.com/articles/InMjei
    [5] http://www.tuicool.com/articles/b2yqeq
    [6] http://www.tuicool.com/articles/jeIVjiy
    [7]http://www.tuicool.com/articles/22au6zV
    [8] http://www.tuicool.com/articles/qqIFvy

    展开全文
  • drools入门

    2011-03-22 11:03:56
    Drools中的Rete算法被称为ReteOO,表示Drools为面向对象系统(Object Oriented systems)增强并优化了Rete算法。 2、规则引擎的优点 声明式编程:使用规则更加容易对复杂的问题进行表述,并得到验证 逻辑与数据...

    文章转载自:http://cwqcwq.iteye.com/blog/397869

    一、背景知识:
    1、什么是规则引擎
    Java规则引擎起源于基于规则的专家系统,而基于规则的专家系统又是专家系统的其中一个分支。专家系统属于人工智能的范畴,它模仿人类的推理方式,使用试探性的方法进行推理,并使用人类能理解的术语解释和证明它的推理结论。
    推理引擎包括三部分:模式匹配器(Pattern Matcher)、议程(Agenda)和执行引擎(Execution Engine)。推理引擎通过决定哪些规则满足事实或目标,并授予规则优先级,满足事实或目标的规则被加入议程。模式匹配器决定选择执行哪个规则,何时执行规则;议程管理模式匹配器挑选出来的规则的执行次序;执行引擎负责执行规则和其他动作。
    和人类的思维相对应,推理引擎存在两者推理方式:演绎法(Forward-Chaining)和归纳法(Backward-Chaining)。演绎法从一个初始的事实出发,不断地应用规则得出结论(或执行指定的动作)。而归纳法则是根据假设,不断地寻找符合假设的事实。Rete算法是目前效率最高的一个 Forward-Chaining推理算法,许多Java规则引擎都是基于Rete算法来进行推理计算的。
    推理引擎的推理步骤如下:
      (1)将初始数据(fact)输入Working Memory。
      (2)使用Pattern Matcher比较规则库(rule base)中的规则(rule)和数据(fact)。
      (3)如果执行规则存在冲突(conflict),即同时激活了多个规则,将冲突的规则放入冲突集合。
      (4)解决冲突,将激活的规则按顺序放入Agenda。
      (5)使用执行引擎执行Agenda中的规则。重复步骤2至5,直到执行完毕所有Agenda中的规则。
      上述即是规则引擎的原始架构,Java规则引擎就是从这一原始架构演变而来的。
    Drools是基于正向推理的规则引擎。正向推理是数据驱动的,facts事实被传递到工作空间中,在那里有一个或多个规则与这些事实匹配,并由Agenda安排执行—我们从一个事实开始,传递事实,最后得到一个结论。
    产生式规则是一个用一阶逻辑进行知识呈现的二元结构。
    when
       
    then
       
    Drools中的Rete算法被称为ReteOO,表示Drools为面向对象系统(Object Oriented systems)增强并优化了Rete算法。

    2、规则引擎的优点
    声明式编程:使用规则更加容易对复杂的问题进行表述,并得到验证
    逻辑与数据分离:数据保存在系统对象中,逻辑保存在规则中。这根本性的打破了面向对象系统中将数据和逻辑耦合起来的局面
    速度及可测量性:Drools的Rete、Leaps算法,提供了对系统数据对象非常有效率的匹配,这些算法经过了大量实际考验的证明
    3、何时使用
    业务逻辑经常发生改变
    代码中有很多”if””else””switch”和其它凌乱的逻辑,且总是易变的

    二、开始

    目前drools的最新版本是5.0(2009年5月19日发布),本文使用4.0.7。

    1、导入jar包:

    drools-core-4.0.7.jar
    drools-compiler-4.0.7.jar
    antlr3-runtime-3.0
    mvel-1.3.1-java1.4
    core-3.2.3.v_686_R32x :在eclipse中编译.drl文件时需要


    2、从HelloWorld开始:

    一个通用的规则引擎类:

    Java代码 复制代码  收藏代码
    1. import java.io.InputStreamReader;   
    2. import java.io.Reader;   
    3.   
    4. import org.drools.RuleBase;   
    5. import org.drools.RuleBaseFactory;   
    6. import org.drools.WorkingMemory;   
    7. import org.drools.compiler.DroolsParserException;   
    8. import org.drools.compiler.PackageBuilder;   
    9. import org.drools.event.DebugWorkingMemoryEventListener;   
    10. import org.drools.rule.Package;   
    11.   
    12. public class RuleEngine {   
    13.   
    14.  private RuleBase rules;   
    15.   
    16.  private boolean debug = false;   
    17.   
    18.  public RuleEngine(String rulesFile) throws DroolsParserException {   
    19.   super();   
    20.   try {   
    21.    //读取规则文件,*.drl   
    22.    Reader source = new InputStreamReader(RuleEngine.class.getResourceAsStream(&quot;/&quot; + rulesFile));   
    23.       
    24.    //PackageBuilder用来构建Package   
    25.    PackageBuilder builder = new PackageBuilder();   
    26.   
    27.    //解析和编译规则文件   
    28.    builder.addPackageFromDrl(source);   
    29.   
    30.    //获取包中的规则集合   
    31.    Package pkg = builder.getPackage();   
    32.   
    33.    //RuleBase是运行时组件,包含一个或多个Package   
    34.    rules = RuleBaseFactory.newRuleBase();   
    35.   
    36.    rules.addPackage(pkg);   
    37.   } catch (Exception e) {   
    38.    throw new DroolsParserException(&quot;Could not load/compile rules file: &quot; + rulesFile, e);   
    39.   }   
    40.  }   
    41.   
    42.  public void executeRules(WorkingEnvironmentCallback callback) {   
    43.   WorkingMemory workingMemory = rules.newStatefulSession();   
    44.   if (debug) {   
    45.    workingMemory.addEventListener(new DebugWorkingMemoryEventListener());   
    46.   }   
    47.   callback.initEnvironment(workingMemory);//用来向Working Memory中设置Facts对象   
    48.   workingMemory.fireAllRules();//触发规则引擎   
    49.  }   
    50.   
    51. }  
    import java.io.InputStreamReader;
    import java.io.Reader;
    
    import org.drools.RuleBase;
    import org.drools.RuleBaseFactory;
    import org.drools.WorkingMemory;
    import org.drools.compiler.DroolsParserException;
    import org.drools.compiler.PackageBuilder;
    import org.drools.event.DebugWorkingMemoryEventListener;
    import org.drools.rule.Package;
    
    public class RuleEngine {
    
     private RuleBase rules;
    
     private boolean debug = false;
    
     public RuleEngine(String rulesFile) throws DroolsParserException {
      super();
      try {
       //读取规则文件,*.drl
       Reader source = new InputStreamReader(RuleEngine.class.getResourceAsStream(&quot;/&quot; + rulesFile));
       
       //PackageBuilder用来构建Package
       PackageBuilder builder = new PackageBuilder();
    
       //解析和编译规则文件
       builder.addPackageFromDrl(source);
    
       //获取包中的规则集合
       Package pkg = builder.getPackage();
    
       //RuleBase是运行时组件,包含一个或多个Package
       rules = RuleBaseFactory.newRuleBase();
    
       rules.addPackage(pkg);
      } catch (Exception e) {
       throw new DroolsParserException(&quot;Could not load/compile rules file: &quot; + rulesFile, e);
      }
     }
    
     public void executeRules(WorkingEnvironmentCallback callback) {
      WorkingMemory workingMemory = rules.newStatefulSession();
      if (debug) {
       workingMemory.addEventListener(new DebugWorkingMemoryEventListener());
      }
      callback.initEnvironment(workingMemory);//用来向Working Memory中设置Facts对象
      workingMemory.fireAllRules();//触发规则引擎
     }
    
    }
    



    3、编写drl文件:test.drl

    Java代码 复制代码  收藏代码
    1.   
    2. package org.drools.tutorials.banking   
    3.   
    4. rule &quot;Rule 01&quot;      
    5.     when   
    6.         String (toString==&quot;jack&quot;) //含义:如果插入的Facts对象是String类型,且调用其toString()方法后的值等于&quot;jack&quot;,则为true   
    7.     then   
    8.         System.out.println(&quot;HelloWorld!&quot;);   
    9. end  
    package org.drools.tutorials.banking
    
    rule &quot;Rule 01&quot;   
        when
            String (toString==&quot;jack&quot;) //含义:如果插入的Facts对象是String类型,且调用其toString()方法后的值等于&quot;jack&quot;,则为true
        then
            System.out.println(&quot;HelloWorld!&quot;);
    end
    



    4、测试:

    Java代码 复制代码  收藏代码
    1. public class Test {   
    2.   
    3.  public static void main(String[] args) {    
    4.   RuleEngine engine = null;   
    5.   try {   
    6.    engine = new RuleEngine(&quot;test.drl&quot;);   
    7.   } catch (DroolsParserException e) {   
    8.    // process Exception   
    9.   }   
    10.   engine.executeRules(new WorkingEnvironmentCallback(){   
    11.    public void initEnvironment(WorkingMemory workingMemory) throws FactException {       
    12.     workingMemory.insert(&quot;jack&quot;); //向Working Memory中设置Facts对象      
    13.    }      
    14.   });     
    15.  }   
    16. }  
    public class Test {
    
     public static void main(String[] args) { 
      RuleEngine engine = null;
      try {
       engine = new RuleEngine(&quot;test.drl&quot;);
      } catch (DroolsParserException e) {
       // process Exception
      }
      engine.executeRules(new WorkingEnvironmentCallback(){
       public void initEnvironment(WorkingMemory workingMemory) throws FactException {    
        workingMemory.insert(&quot;jack&quot;); //向Working Memory中设置Facts对象   
       }   
      });  
     }
    }
    
    



    三、简单介绍

    1、术语解释

    Rule:一条规则可以看作是IF...THEN...语句块,或者一个简单的IPO(即输入、处理和输出),描述了一组输入,一组判断和一组输出;
    RuleBase: RuleBase包含一个或多个规则包,它们已经被校验和编译完成,是可以序列化的
    Package: 规则包,是规则以及其它相关结构的一个集合,包必须有一个名称空间,并且使用标准的java约定进行命名
    WorkingMemory: 用户工作区,包含用户的数据和相关Rule的引用
    Facts: Facts就是规则中用到的输入,Facts可以是任何规则可以存取的Java对象,规则引擎完全不会克隆对象,它仅仅是保存对对象的一个引用/指针

    2、规则文件详解
    规则文件通常是以drl扩展名结尾。在一个drl文件中可以包含多个规则,函数等等,DRL是简单的text文件格式。

    规则文件的构成:

    package package-name //定义包名
    imports   //导入java包
    globals   //定义全局变量,如 global java.util.List myGlobalList;
    functions  //定义函数
    rules   //一系列的规则

    规则的构成:

    rule &quot;name&quot;
        attributes
        when
            LHS
        then
            RHS
    end

    说明:
    LHS是规则的条件部分,可以定义变量
    RHS是允许Java语义代码,RHS中的多条语句实质上是一个规则,只有满足全部语句才符合规则
    任何在LHS中绑定的变量可以在RHS中使用

    3、规则文件示例解读

    rule "Rule 01"  
        when
    //$date定义一个变量,其值为Cashflow对象getDate()的值
    //$cashflow定义一个指向Cashflow对象的引用
            $cashflow : Cashflow( $date : date, $amount : amount )
            not Cashflow( date < "27-Oct-2007") //not 意为不存在,只有不存在date < "27-Oct-2007"的Cashflow对象才为true
        then
            System.out.println("Cashflow: "+$date+" :: "+$amount);
    $cashflow.setAmount($cashflow.getAmount()+$amount); //设置Cashflow对象的amount值
            retract($cashflow);//当retract一个fact,WorkingMemory将不再跟踪该fact
    end

    public class Cashflow {
        private Date   date;
        private double amount;
        //省略getter.. setter..
    }

    重要:规则引擎完全不会克隆对象,它仅仅是保存对对象的一个引用/指针
    即,在规则定义中对fact的修改,就是对代码中fact对象的修改。
    也即,规则的根本目的是产生一个供使用的输出结果,即修改后的JavaBean

    展开全文
  • Drools入门手册.ppt

    2009-09-16 11:05:15
    Drools入门手册.ppt Drools入门手册.ppt Drools入门手册.ppt Drools入门手册.ppt
  • 规则引擎Drools入门

    2018-12-03 18:57:56
    规则引擎Drools入门 前言 1.是什么(Drools东东) *名词描述: 2.为什么(要使用Drools) 3.怎么做(来使用Drools) 规则引擎Drools入门 前言 初次接触规则引擎,是由于项目的需要进行了学习与开发应用。 废话不多...
  • 通过一个Drools入门案例来让大家初步了解Drools的使用方式、对Drools有一个整体概念。 业务场景说明 业务场景:消费者在图书商城购买图书,下单后需要在支付页面显示订单优惠后的价格。具体优惠规则如下: 规则...
  • Drools入门系列(一)HelloWorld Drools入门系列(二)HelloWorld详解之Sample.drl Drools入门系列(三)HelloWorld详解之kmodule.xml Drools入门系列(四)HelloWorld详解之JUnit Test类 Drools入门系列(五)...
  • Drools入门手册

    2009-07-20 22:01:41
    drools最好的入门手册,drools最好的入门手册
  • 入门案例 创建一个简单的SpringBoot项目 选择依赖的时候,添加一个web依赖即可 在新项目的pom.xml中添加drools的相关依赖 <properties> <java.version>1.8</java.version> <drools....
  • Drools入门学习

    千次阅读 2017-04-18 17:19:28
    Eclipse安装Drools插件具体步骤参见另外博客:http://blog.csdn.net/shenhaiwen/article/details/70230103Eclipse中添加Drools的运行环境、1下载插件地址:http://www.drools.org/download/download.html2...
  • 本文参考自:Drools6.4 Eclipse插件安装、Drools入门-实现评分专家系统、Drools6.3.0部署(MyEclipse安装与tomcat部署) 1. 下载eclipse插件 在官网下载eclipse插件 drools-distribution-6.3.0.Final.zip 和...
  • Drools入门笔记

    2020-08-28 15:29:49
    1.基本介绍和使用 ------------------------别人✍的不错的--------------------------- 2. 结合springboot demo ----------------------------demo地址----------------------------------
  • Springboot + Drools入门

    千次阅读 2019-05-29 18:01:43
    目前正在进行入门学习,感觉drools的使用还是非常方便的。 对于drools的优点、作用和具体的使用教程还请自行查阅资料,这里仅仅使用使用springboot+drools搭建一个小demo. 1.项目结构 2.pom.xml文件 关于pom.xml...
  • drools入门笔记

    2020-03-06 12:04:02
    Drools是一款基于Java的开源规则引擎,实现了将业务决策从应用程序中分离出来。 优点: 简化系统架构,优化应用 提高系统的可维护性和维护成本 方便系统的整合 减少编写“硬代码”业务规则的成本和风险 Fact对象:...
  • Drools入门到实战业务规则管理系统(BRMS)视频教程 ├─讲义及资料.zip │ ├─01-规则引擎Drools-问题引出 │ 01-课程介绍.mp4 │ 02-问题引出(业务规则说明).mp4 │ 03-问题引出(传统实现方式).mp4 │ ├─...
  • 规则引擎学习
  • Drools入门-搭建

    2019-06-18 14:52:11
    搭建Drools 增加pom依赖文件 <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.7.0.Final</version> &l...
  • 开始drools入门helloworld,一直遇到这个错误。按照网上的案例做了很多遍,最后原来是目录结构的问题,drl文件目录结构要与java文件目录结构一致 这个否这一致会报错!!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,389
精华内容 555
关键字:

drools入门