Drools代替复杂业务

DROOLS

  • 具有一个易于访问企业策略、易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快、效率高。业务分析师或审核人员可以利用它轻松查看业务规则,从而检验是否以编码的规则执行了所需的业务规则。
  • 用XML节点来规范IF-Then句式和事实的定义,使引擎干起活来很舒服。而使用java、groovy等原生语言来做判断和执行语句,让程序员很容易过渡、移植,学习曲线很低。

规则引擎 BRMS

  • 规则引擎,全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。

需要注意的是规则引擎并不是具体的技术框架,而是指的一类系统,即业务规则管理系统。目前市面上具体的规则引擎产品有:drools、VisualRules、iLog等。

规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出平台。

系统中引入规则引擎后,业务规则不再以程序代码的形式驻留在系统中,取而代之的是处理规则的规则引擎,业务规则存储在规则库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务的规则等。业务规则被加载到规则引擎中供应用系统调用。

使用规则引擎的优势

  • 业务规则与系统代码分离,实现业务规则的集中管理。
  • 在不重启服务的情况下可随时对业务规则进行扩展和维护。
  • 可以动态修改业务规则,从而快速响应需求变更,大大提高了对复杂逻辑代码的可维护性。
  • 规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则。
  • 减少了硬编码业务规则的成本和风险。
  • 使用规则引擎提供的规则编辑工具,是复杂的业务规则实现变得简单。

规则引擎应用场景

对于一些存在比较复杂得业务规则并且业务规则会频繁变动的系统比较适合使用规则引擎:

  • 风险控制系统————风险贷款、风险评估
  • 反欺诈项目——————银行贷款、征信验证
  • 决策平台系统————财务计算
  • 促销平台系统————满减、打折、加价购 等等

Drools

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

在项目中使用drools时,既可以单独使用也可以整合spring使用。如果单独使用只需要导入如下maven座标即可:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.6.Final</version>
</dependency>

如果我们使用IDEA开发drools应用,IDEA中已经集成了drools插件。如果使用eclipse开发drools应用还需要单独安装drools插件。
drools API开发步骤如下
获取KieServices————>获取KieContainer————>KieSession————>Insert fact————>触发规————>关闭KieSession

示例

第一步新建一个Springboot项目
第二部引入Drools
<!--规则引擎-->
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>

第三步在resource下面新建META-INF目录,接着创建kmodule.xml文件

第四步在resource下面新建rules目录,接着创建以drl结尾的文件

使用drools规则引擎主要工作就是编写规则文件,在规则文件中定义跟业务相关的业务规则,例如本案例定义的就是图书优惠规则。规则定义好后就需要调用drools提供的API将数据提供给规则引擎进行规则模式匹配,规则引擎会执行匹配成功的规则并将计算的结果返回给我们。

可能大家会有疑问,就是我们虽然没有在任何代码中编写规则的判断逻辑,但是我们还是在规则文件中编写了业务规则,这跟在代码中编写规则有什么本质的区别呢?

使用规则引擎时业务规则可以做到动态管理。业务人员可以像管理数据一样对业务规则进行管理,比如查询、添加、更新、统计、提交业务规则等。这样就可以做到在不重启服务的情况下调整业务规则。

规则引擎构成
drools规则引擎由以下三部分构成:

  • working Memory(工作内存):drools规则引擎会从Working Memory中获取数据并和规则文件中定义得规则进行模式匹配,所以我们开发得应用程序只需要将我们的数据插入到Working Memory中即可,例如本案例中我们调用kieSession.insert(order)就是将order对象插入到了工作内存中。
  • rule base(规则库):我们在规则文件中定义的规则都会被加载到规则库中。
  • Inference Engine(推理引擎)

Fact:事实,是指在drools规则应用当中,将一个普通的javaBean插入到WorkingMemory后的对象就是Fact对象。例如本案列中的order对象就属于Fact对象。Fact对象是我们的应用和规则引擎进行数据交互的桥梁或通道。

其中Inference Engine(推理引擎)又包括:

  • Pattern matcher(匹配器):将Rule Base中的所有规则与Working Memory中的Fact对象进行模式匹配,匹配成功的规则将被激活并放入Agenda中。
  • Agenda(议程):用于存放通过匹配器进行模式匹配后被激活的规则。
  • Execution Engine(执行引擎):执行Agenda中被激活的规则。

规则引擎执行过程

1.将初始数据(fact)输入至工作内存(Working Memory)
2.使用Pattern Matcher将规则库中的规则(rule)和数据(fact)比较
3.如果执行规则存在冲突(conflict),及同时激活了多个规则,将冲突的规则放入冲突集合。
4.解决冲突,将激活的规则按顺序放入Agenda
5.执行的Agenda中的规则。重复步骤b至e,直到执行完毕Agenda中的所有的规则。

KIE介绍

Kie大部分分类都是以Kie开头。Kie全称为:Knowledge IS Everything,即"只是就是一切"的缩写,是Jboss一系列项目的总称。Kie的主要模块有OptaPlanner、Drools、UberFire、jBPM。

Drools基础语法

1.规则文件构成
在使用Drools时非常重要的一个工作就是编写规则文件,通常规则文件的后缀为.drl。
drl是Drools Rule language的缩写。在规则文件中编写具体的规则内容。
一套完整的规则文件内容构成如下:

关键字 描述
package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import 用于导入类或者静态的方法
global 全局变量
function 自定义函数
query 查询
rule end 规则体

Drools支持的规则文件,除了drl形式,还有Excel文件类型的。

规则体语法结构

规则提是规则文件内容中的重要组成部分,是进行业务规则判断、处理业务结果的部分。
规则体语法结构如下:

rule "ruleName"
    attributes
    when
        LHS
    then
        RHS
end

rule:关键字,表示规则开始,参数为规则的唯一名称。
attributes:规则属性,是rule与when之间参数,为可选项。
when:关键字,后面跟规则的条件部分
LHS(Left Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将被是为始终为true的条件元素。
then:关键字,后面跟规则的结果部分。
RHS(Right Hand Side):是规则的后果或行动部分的通用名称。
end:关键字,表示一个规则结束。

注释

在drl形式的规则文件中使用注释和Java类中使用注释一致,分为单行注释和多行注释。
单行注释用"//“进行标记,多行注释以”/*“开始,以”*/"结束。如下示例:

// 规则rule1的注释,这是一个单行的注释
rule "rule1"
    when
    then
        System.out.println("rule触发");
end

/*
规则rule2的注释,
这是一个多行的注释
*/
rule "rule2"
    when
    then
        System.out.println("rule2触发");
end

Pattern模式匹配

前面我们已经知道了Drools中的匹配器可以将Rule Base中的所有规则与Working Memory中的fact对象进行模式匹配,那么我们就需要在规则体的LHS部分定义规则并进行模式匹配。LHS部分由一个或者多个条件组成,条件又称为pattern。

pattern的语法结构为:绑定变量名:Object(Field约束)
其中绑定变量明可以省略,通常绑定变量名的命名一般建议以$开始。如果定义了绑定变量名,就可以在规则体的RHS部分使用此绑定变量名来操作相应的Fact对象。Field约束部分是需要返回true或者false的0个或多个表达式。

例如我们的案例:

// 规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        // Order为类型约束,originalPrice为属性约束
        $order:Order(originalPrice < 200 && originalPrice >= 100);
    then
        $order.setRealPrice($order.getOriginalPrice() - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200的优惠20元");
end

通过上面的例子我们可以知道,匹配的条件为:
1.工作内存中必须在Order这种类型的Fact对象----类型约束
2.Fact对象的originalPrice属性值必须小于200----属性约束
3.Fact对象的originalPrice属性值必须大于等于100----属性约束
以上条件必须同时满足当前规则才有可能被激活。

绑定变量可以用在对象上,也可以用在对象的属性上。例如上面的例子可以改为:

// 规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100);
    then
        System.out.println("$op =" + $op);
        $order.setRealPrice($order.getOriginalPrice - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200的优惠20元");
end

LHS部分还可以定义多个pattern,多个pattern之间可以使用and 或者or进行连接,也可以不写,默认连接为and。

// 规则二:所购图书总价在100到200元的优惠20元
rule "book_discount_2"
    when
        $order:Order($op:originalPrice < 200 && originalPrice >= 100) and 
        $customer:Customer(age > 20 && gender == 'male');
    then
        System.out.println("$op =" + $op);
        $order.setRealPrice($order.getOriginalPrice - 20);
        System.out.println("成功匹配到规则二:所购图书总价在100到200的优惠20元");
end

比较操作符

Drools提供的比较操作符,如下表:

符号 说明
> 大于
< 小于
>= 大于等于
<= 小于等于
== 等于
!= 不等于
contains 检查一个Fact对象的某个属性值是否包含一个指定的对象值
not contains 检查一个Fact对象的某个属性值是否不包含一个指定的对象值
memberOf 判断一个fact对象的某个属性是否在一个或多个集合中
not memberOf 判断一个fact对象的某个属性是否不在一个或多个集合中
matches 判断一个Fact对象的属性是否与提供的标准的java正则表达式进行匹配
not matches 判断一个Fact对象的属性是否不与提供的标准的java正则表达式进行匹配

前6个比较操作符和java中的完全相同,下面我们重点学习后6个比较操作符

  • contains | not contains 语法结构
    object(field[Collection/Array]contains value)
    object(field[Collection/Array] not contains value)
  • memberOf | not memberOf 语法结构
    object(field memberOf value [Collection/Array])
    object(field not memberOf value [Collection/Array])
  • matches | not matches 语法结构
    object(field matches “正则表达式”)
    object(field not matches “正则表达式”)

关键字

Drools关键字分为:硬关键字(Hard Keywords)和软关键字(Soft keywords).
硬关键字是我们在规则文件中定义包名或者规则名时明确不能使用的,否则程序会报错。软关键字虽然可以使用,但是不建议使用。
硬关键字包括:true、false、null
软关键字包括:lock-on-active、date-effective、date-expire、no-loop、auto-focus、activation-group、agenda-group、ruleflow-group、entry-point、duration、package、import、dialect、salience、enabled、attributes、rule、extend、when、then、template、query、declare、function、global、eval、not、in、or、and、exists、forall、accumulate、collect、from、action、reverse、result、end、over、init

Drools内置方法

规则文件的RHS部分的主要作用是通过插入,删除或修改工作内存中的Fact数据,来达到控制规则引擎执行的目的。Drools提供了一些方法可以用来操作工作内存中的数据,操作完成后规则引擎会重新进行相关规则的匹配,原来没有匹配成功的规则在我们修改数据完成后有可能就会匹配成功了。

Update方法的作用是更新工作内存中的数据,并让相关的规则重新匹配。在更新数据时需要注意防止发生死循环。

insert方法的作用是向工作内存中插入数据,并让相关的规则重新匹配。

retract方法的作用是删除工作内存中的数据,并让相关的规则重新匹配

执行顺序默认是按照编写规则的优先级,可以使用salience来设置优先级

规则属性

attributes

属性名 说明
salience 指定规则行优先级
dialect 指定规则使用的语言类型,取值为java和mvel
enabled 指定规则是否启动
date-effective 指定规则生效时间
date-expires 指定规则失效时间
activation-group 激活分组,具有相同组名称的规则只能有一个规则触发
agenda-group 议程分组,只有获取焦点的组中的规则才有可能触发
timer 定时器,指定规则触发的时间
auto-focus 自动获取焦点,一般结合agenda-group一起使用
no-loop 防止死循环
enabled属性

enabled属性对应的取值为true和false,默认为true。用于指定当前规则是否启用,如果设置的值为false则当前规则无论是否匹配成功都不会触发。

dialect属性

dialect属性用于指定当前规则使用的语言类型,取值为java和mvel,默认为java。
注:mvel是一种基于java语言的表达式语言。
mvel向正则表达式一样,有直接支持集合、数组和字符串匹配的操作符。
mvel还提供了用来配置和构造字符串的模板语言。
mvel表达式内容包括属性表达式,布尔表达式,方法调用,变量赋值,函数定义等。

salience属性

salience属性用于指定规则的执行优先级,取值类型为Integer。数值越大越优先执行。每个规则都有一个默认的执行顺序,如果不设置salience属性,规则体的执行顺序为由上到下。

no-loop属性

no-loop属性用于防止死循环,当规则通过update之类的函数修改了Face对象时,可能使当前规则再次被激活而导致死循环。取值类型为Boolean,默认值为false。

activation-group属性

activation-group属性是指激活分组,取值为String类型。具有相同的分组名称的规则只能有一个规则被触发。
同一个分组中的多个规则如果都能匹配成功,具体哪一个最终能够被触发可以通过salience属性确定。

agenda-group属性

agenda-group属性为议程分组,属于另一种可控制的规则执行方式。用户可以通过设置agenda-group来控制规则的执行,只有获取焦点的组中的规则才会被触发。

auto-focus属性

auto-focus属性为自动获取焦点,取值类型为Boolean,默认值为false。一般结合agenda-group属性使用,当一个议程分组为获取焦点时,可以设置auto-focus属性来控制。

timer属性

timer属性可以通过定时器的方式指定规则执行的时间,使用方式有两种:

方式一:timer(int:?)
此种方式遵循java.util.Timer对象的使用方式,第一个参数表示几秒后执行,第二个数表述每隔几秒执行一次,第二个参数为可选。
方式二:timer(cron:)
此种方式使用标准的unix cron表达式的使用方式来定义规则执行的时间。

date-effective属性

date-effective属性用于指定规则的生效时间,即只有当前系统时间大于等于设置的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。

date-expires属性

date-expires属性用于指定规则的失效时间,即只有当前系统时间小于的时间或者日期规则才有可能触发。默认日期格式为:dd-MMM-yyyy。用户也可以自定义日期格式。

Drools高级语法

关键字 描述
package 包名,只限于逻辑上的管理,同一个包名下的查询或者函数可以直接调用
import 用于导入类或者静态方法
global 全局变量
function 自定义函数
query 查询
rule end 规则体
global全局变量

global关键字用于在规则文件中定义全局变量,它可以让应用程序的对象在规则文件中能被访问。可以用来为规则文件提供数据或服务。

语法结构为:global对象类型 对象名称
在使用global定义的全局变量时有两点需要注意:
1.如果对象类型为包装类型时,在一个规则中改变了global的值,那么只针对当前规则有效,对其他规则中的global不会有影响。可以理解为它是当前规则代码中的global副本,规则内部修改不会影响全局的使用。
2.如果对象类型为集合类型或javaBean时,在一个规则中改变了global的值,对java代码和所有规则都有效。

query查询

query查询提供了一种查询working memory中符合约束条件的fact对象的简单方法。它仅包含规则文件中的LHS部分,不用指定“when”和“then”部分并且以end结束。语法如下:

query 查询的名称(可选参数)
    LHS
end
function函数

function关键字用于在规则文件中定义函数,就相当于java类中的方法一样。可以在规则体中调用定义的函数。使用函数的好处是可以将业务逻辑集中放置在一个地方,根据需要可以对函数进行修改。
函数定义的语法结构如下:

function 返回值类型 函数名(可选参数){
    // 逻辑代码
}
LHS加强

我们已经知道了在规则体中的LHS部分是介于when和then之间的部分,主要用于模式匹配,只有匹配结果为true时,才会触发RHS部分的执行。

符合值限制 in/not in

复合值限制是指超过一种匹配值的限制条件,类似于SQL语句中的in关键字。Drools规则体中的LHS部分可以使用in或not in进行复合值的匹配。具体语法结构如下:
Object(field in(比较值1,比较值2…))

举例:

$s:Student(name in ("张三","李四","王五"))
$s:Student(name not in ("张三","李四","王五"))
条件元素eval

eval用于规则体的LHS部分,并返回一个Boolean类型的值。
eval(表达式)
举例:

eval(true)
eval(false)
eval(1 == 1)
条件元素not

not用于判断working memory中是否存在某个Fact对象,如果不存在则返回true,如果存在则返回false。
not object(可选属性约束)
举例:

not Student()
not Student(age < 10)
条件元素exists

exists的作用与not相反,用于判断Working Memory中是否存在某个Fact对象,如果存在则返回true,不存在则返回false。
exists Object(可选属性约束)
举例:

exists Student()
exists Student(age <10 && name != null)

在LHS部分进行条件编写时并没有使用exists也可以达到判断WorkingMemory中是否存在某个符合条件的Fact元素的目的。
区别:当向Working Memory中加入多个满足条件的Fact对象时,使用了Exists的规则执行一次,不使用exists的规则会执行多次。

规则继承

规则之间可以使用extends 关键字进行规则条件部分的继承,类似于java类之间的继承
例如:

rule "rule_1"
    when
        Syudent(age > 10)
    then
        System.out.println("rule_1 执行了。。。。")
end

rule "rule_2" extends "rule_1" //继承上面的规则
    when
        //此处的条件虽然只写了一个,但是从上面的规则继承了一个条件,所以当前规则存在两个条件,即Student(age<20)和Student(age>10)
        Student(age <20)
    then
        System.out.println("rule_2 执行了")
end
RHS加强

RHS部分是规则体的重要组成部分,当LHS部分的条件匹配成功后,对应的RHS部分就会触发执行。一般在RHS部分中需要进行业务处理。
在RHS部分Drools为我们提供了一个内置对象,名称就是drools。

halt

halt方法的作用是立即终止后面所有规则的执行

getWorkingMemory

getWorkingMemory方法的作用是返回工作内存对象

getRule

getRule方法的作用是返回规则对象。

规则文件编码规范

在进行drl类型的规则文件编写时尽量遵循如下规范:

  • 所有的规则文件(.drl)应统一放在一个规定的文件夹中,如:/rule文件夹
  • 书写的每个规则应尽量加上注释。注释要清晰明了,言简意赅
  • 同一类型的对象尽量放在一个规则文件中。如所有Student类型的对象尽量放在一个规则文件中
  • 规则结果部分(RHS)尽量不要有条件语句,如if(…),尽量不要有复杂的逻辑和深层次的嵌套语句
  • 每个规则最好都加上salience属性,明确执行顺序
  • Drools默认dialect为“java”,尽量避免使用dialect “mvel”

Spring 整合Drools

在项目中使用Drools时往往会跟Spring整合来使用。
第一步:创建maven工程Drools_spring并配置pom.xml

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools</artifactId>
    <version>7.10.0.Final</version>
</dependency>
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.10.0.Final</version>
    <!--注意:此处必须排除传递过来的依赖,否则会跟我们自己导入的spring jar包产生冲突-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>

建立spring.xml

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:kie="http://drools.org/schema/kie-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://drools.org/schema/kie-spring
                            http://drools.org/schema/kie-spring.xsd">

    <kie:kmodule id="kmodule">
        <kie:kbase name="kbase" packages="rules">
            <!--package 代表目录-->
            <kie:ksession name="ksession"></kie:ksession>
        </kie:kbase>
    </kie:kmodule>
    <bean class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"></bean>
</beans>

SpringBoot集成Drools
首先引入相关jar包

<!--规则引擎-->
<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-compiler</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-templates</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-api</artifactId>
    <version>7.10.0.Final</version>
</dependency>

<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.10.0.Final</version>
    <!--注意:此处必须排除传递过来的依赖,否则会跟我们自己导入的spring jar包产生冲突-->
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>

相关配置文件

package com.panion.space.config;

import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

/**
 * @ClassName DroolsConfig
 * @Description TODO
 * @Version 1.0
 */
@Configuration
public class DroolsConfig {

	private static final String RULES_PATH = "rules/";

	private final KieServices kieServices = KieServices.Factory.get();

	@Bean
	@ConditionalOnMissingBean
	public KieFileSystem kieFileSystem()throws IOException{
		KieFileSystem kieFileSystem = kieServices.newKieFileSystem();

		ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
		Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
		String path = null;
		for(Resource file : files){
			path = RULES_PATH + file.getFilename();
			kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
		}
		return kieFileSystem;
	}

	@Bean
	@ConditionalOnMissingBean
	public KieContainer kieContainer() throws IOException{
		KieRepository kieRepository = kieServices.getRepository();
		kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
		KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
		kieBuilder.buildAll();
		return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
	}
	@Bean
	@ConditionalOnMissingBean
	public KieBase kieBase() throws IOException{
		return kieContainer().getKieBase();
	}
	@Bean
	@ConditionalOnMissingBean
	public KModuleBeanFactoryPostProcessor kiePostProcessor() throws IOException{
		return new KModuleBeanFactoryPostProcessor();
	}
}

WorkBench

简介
WorkBench是Kie组件中的元素,也称为KIE-WB,是Drools-WB与HBPM-WB的结合体。它是一个可视化的规则编辑器。WorkBench其实就是一个war包,安装到tomcat中就可以运行。使用WorkBench可以在浏览器中创建数据对象、创建规则文件、创建测试场景并将规则部署到maven仓库供其他应用使用。

1.下载tomcat8
2.下载workbench war包 https://download.jboss.org/drools/release/7.6.0.Final/kie-drools-wb-7.6.0.Final-tomcat8.war
3.需要3个jar包,放到tomcat/lib下面
kie-tomcat-integration-7.10.0.Final.jar
javax.security.jacc-api-1.5.jar
slf4j-api-1.7.25.jar
4.tomcat/bin目录下创建setenv.bat

CATALINA_OPTS="-Xmx512M \
    -Djava.security.auth.login.config=$CATALINA_HOME/webapps/kie-drools-wb/WEB-INF/classes/login.config \
    -Dorg.jboss.logging.provider=jdk"

5.在tomcat/conf/server.xml文件中host标签之间加入代码

<Valve className="org.kie.integration.tomcat.JACCValve" />

6.在tomcat/conf/tomcat-users.xml文件中添加角色用户

<tomcat-users >
  <role rolename="admin"/>
  <user username="admin" password="admin" roles="admin"/>
</tomcat-users>

workbench可以操作创建类、规则文件、检验规则文件、创建测试场景、构建、部署

我们可以在idea中开发项目不编写规则文件,规则文件我们通过workbench开发安装部署到maven仓库中,我们自己开发的项目只需要远程加载maven仓库中的jar包就可以完成规则的调用。这种开发方式的好处是我们的应用可以和业务规则完全分离,同时通过workbench修改规则后我们的应用不需要任何修改就可以加载到最新的规则从而实现规则的动态变更。

决策表

Drools除了支持drl形式的文件外还支持xls格式文件(即Excel文件)。这种xls格式的文件通常称为决策表(decision table)。
决策表是一个“精确而紧凑的”表达条件逻辑方式,非常适合商业级别的规则。决策表与现有的drl文件可以无缝替换。Drools提供了相应的API可以将xls文件编译为drl格式的字符串。

关键字 说明 是否必须
ReleSet 相当于drl文件中的package 必须,只能有一个如果没有设置RuleSet对应值则使用默认值rule_table
Sequential 取值为boolean类型。true表示规则按照表格自上到下的顺序执行,,false表示乱序 可选
Import 相当于drl文件中的import,如果引入多个类则类之间用逗号分隔 可选
Variables 相当于drl文件中的global,用于定义全局变量,如果有多个全局变量则中间用逗号分离 可选
RuleTable 它指示了后面将会有一批rule,RuleTable的名称将会作为以后生成rule的前缀 必须
CONDITION 规则条件关键字,相当于drl文件中的when。下面两行则表示LHS部分,第三行则为注释行,不计为规则部分,从第四行开始,每一行表示一条规则 每个规则表至少有一个
ACTION 规则结果关键字,相当于drl文件中的then 每个规则表至少有一个
NO-LOOP 相当于drl文件中的no-loop 可选
AGENDA-GROUP 相当于drl文件中的agenda-group 可选

在决策表中还经常使用到占位符,语法为$后面加数字,用于替换每条规则中设置的具体值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章