熟练使用Drools规则引擎

介绍
规则引擎全称为业务规则管理系统,英文名称为BRMS 就像是一个数据库 只不过规则引擎存储的都是业务的规则数据 我们可以在规则引擎上对每个规则进行配置 添加或者修改 常用的规则引擎就有drools 作用就是接收数据的输入后 然后对数据进行规则校验 最后符合规则的数据在做数据的输出

使用规则引擎的优点?

  1. 代码和业务规则进行分离 并且规则可以集中管理
  2. 在不重启服务的情况下对业务规则进行扩展和维护
  3. 可以动态的修改业务规则 实现快速响应需求的变更

什么样的场景适合使用规则引擎?
比较复杂的业务规则并且业务规则会频繁变动的系统适合使用规则引擎

入门案例

导入依赖

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

在项目中创建resources/META-INF/kmodule.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">

    <!--
        name:指定kbase名称 唯一
        packages:指定规则文件 根据创建的规则文件来写 否则检测不到
        default:当前kabse是否为默认
      -->
    <kbase name="kbase" packages="test" default="true">
        <!--
            name:指定ksession名称 唯一
            default:指定当前ksession是否为默认
        -->
        <ksession name="ksession-test" default="true"/>
    </kbase>

</kmodule>在这里插入代码片

创建实体类

@Data
public class OrderDTO {

    /**
     * 价格
     */
    private BigDecimal price;

    /**
     * 名称
     */
    private String name;



}

在项目resources/test/order.drl创建drl文件

在这里插入图片描述
编写第一条规则

package drosl.order;

import com.macro.mall.dto.OrderDTO;

// rule: 规则的唯一名称
// when:条件判断体
// then:规则执行体
// end:表示规则结束
rule "规则1、如果订单金额大于1000则触发此规则"
    when
        $order:OrderDTO(price > 1000)
    then
        System.out.println("规则1触发了,金额大于了1000元,当前的金额为 = " + $order.getPrice());
    end

创建测试类

    public static void main(String[] args) {
        KieServices kieServices = KieServices.Factory.get();
        // 创建kie容器对象
        KieContainer kieContainer = kieServices.newKieClasspathContainer();
        // 从kie容器对象中获取会话对象
        KieSession session = kieContainer.newKieSession();
        // 创建Order对象
        OrderDTO dto = new OrderDTO();
        // 赋值测试数据
        dto.setPrice(new BigDecimal("20000"));
        // 将Order对象保存到工作内存当中
        session.insert(dto);
        // 激活规则 Drools会自动匹配规则 匹配成功则执行规则
        session.fireAllRules();

    }

执行结果
在这里插入图片描述

语法说明

package drosl.order;

import com.macro.mall.dto.OrderDTO;
import com.macro.mall.dto.CsDto;

// rule: 规则的唯一名称
// when:条件判断体
// then:规则执行体
// end:表示规则结束
rule "规则1、如果订单金额大于1000则触发此规则"
    when
        // $order:表示该对象的名称 可以为任意
        $order:OrderDTO(price > 1000)
        $cs:CsDto(name = "张三" && age > 18)
        // 也可以写多个条件 可以用and 或者 or 拼接 如果不写 默认为and
    then
        // $order.getPrice():因为上面该对象已经取名$order 所以就可以直接用$order 获取对象的值
        System.out.println("规则1触发了,金额大于了1000元,当前的金额为 = " + $order.getPrice());
    end

关键字解释

关键字描述
packagedrools文件名称,可以随意
import导入类或者静态方法 只有导入的类和静态方法 drools才可以使用
global全局变量
function自定义函数
query查询
rule end规则体

关键字描述
rule规则名称 可以随意。但是必须唯一 可以是英文也可以是汉字
attributes规则属性。是rule与when之间的参数 非必写
when所有的规则条件都在when下写
LHS是规则条件的通用名称 由一个或者多个条件组成 如果LHS为空 则它将被视为true
then所有的执行体都在then下写
RHS是执行体的通用名称
end表示规则结束

比较符解释

关键字描述
>大于
<小于
>=大于等于
<=小于等于
==等于
!=不等于
contains判断一个对象的某个属性值是否包含一个指定对象的值
not contains判断一个对象的某个属性值是否不包含一个指定的对象值
memberOf判断一个对象的某个属性是否在一个或多个集合中

内置方法说明

  • update 方法
rule "规则2、测试规则内置方法"
    when
        $order:OrderDTO(price > 1000)
    then
        System.out.println("规则2触发了,update方法前的金额为 = " + $order.getPrice());
        $order.setPrice(new BigDecimal("10"));
        update($order);
        System.out.println("规则2触发了,update方法后的金额为 = " + $order.getPrice());
    end

rule "规则3、测试规则内置方法"
    when
        $order:OrderDTO(price == 10)
    then
        System.out.println("规则3触发了,当前的金额为 = " + $order.getPrice());
    end
    public static void main(String[] args) {
        KieServices kieServices = KieServices.Factory.get();
        // 创建kie容器对象
        KieContainer kieContainer = kieServices.newKieClasspathContainer();
        // 从kie容器对象中获取会话对象
        KieSession session = kieContainer.newKieSession();
        // 创建Order对象
        OrderDTO dto = new OrderDTO();
        // 赋值测试数据
        dto.setPrice(new BigDecimal("20000"));
        // 将Order对象保存到工作内存当中
        session.insert(dto);
        System.out.println("规则执行前 对象的金额为 = "+ dto.getPrice());
        // 激活规则 Drools会自动匹配规则 匹配成功则执行规则
        session.fireAllRules();
        System.out.println("规则执行后 对象的金额为 = "+ dto.getPrice());

    }

在这里插入图片描述

从执行结果可以看出 update执行后将会对对象的属性修改。并且修改后 规则文件会重新执行。

  • insert 方法
rule "规则4、测试规则内置方法"
    when

    then
        OrderDTO dto = new OrderDTO();
        System.out.println("规则4触发了,insert方法前的金额为 = " + dto.getPrice());
        dto.setPrice(new BigDecimal("10"));
        insert(dto);
        System.out.println("规则4触发了,insert方法后的金额为 = " + dto.getPrice());
    end


rule "规则5、测试规则内置方法"
    when
        $order:OrderDTO(price == 10)
    then
        System.out.println("规则5触发了,当前的金额为 = " + $order.getPrice());
    end
    public static void main(String[] args) {
        KieServices kieServices = KieServices.Factory.get();
        // 创建kie容器对象
        KieContainer kieContainer = kieServices.newKieClasspathContainer();
        // 从kie容器对象中获取会话对象
        KieSession session = kieContainer.newKieSession();
        // 创建Order对象
        OrderDTO dto = new OrderDTO();
        // 将Order对象保存到工作内存当中
        session.insert(dto);
        System.out.println("规则执行前 对象的金额为 = "+ dto.getPrice());
        // 激活规则 Drools会自动匹配规则 匹配成功则执行规则
        session.fireAllRules();
        System.out.println("规则执行后 对象的金额为 = "+ dto.getPrice());

    }

在这里插入图片描述

从执行结果可以看出 对对象insert值后 规则文件也会重新匹配 但是和update不同的是 insert的值只限于工作内存当中

  • retract 方法
rule "规则6、测试规则内置方法"
    when
       $order:OrderDTO(price == 10000)
    then
        retract($order);
    end

基本属性

关键字描述
enabled指定当前的规则是否启用 默认为true
dialect选择当前规则的语言类型 比如是java/mvel 默认为java
salience指定执行的优先级 数值越高越先执行
no-loop作用是防止出现死循环 因为当通过修改对对象操作之后 规则就会重新校验 这样当前的这个规则可能就会被在次的激活 从而导致循环执行 默认为false
activation-group作用是创建规则分组 在相同的组内的规则只能有一个被触发 取值为String类型
agenda-group可以设置焦点的分组 比如我设置了两个组 我只想用组1的规则 那么我就需要在java代码中设置焦点设置 设置的组才可以执行校验 没有的则不会执行
auto-focus作用是自己给自己设置焦点 只能在agenda-group 分组下使用 当java代码没有设置焦点的时候 该分组如果想要被执行 那么就可以自己给自己设置焦点 默认为false
timer可以指定几秒后执行 或者几秒后执行然后每隔几秒在执行
date-effectice作用是指定规则生效的时间 当系统的时间大于设置的时间才会执行 时间的格式为yyyy-MM-dd HH:mm:ss
date-expires作用是指定规则的失效时间 当系统的时间小于设置的时间才会出发 时间的格式为yyyy-MM-dd HH:mm:ss

高级语法

  1. global:设置全局变量
global java.lang.Integer count

global java.util.List list

rule "规则8、测试高级语法"
    when

    then
        System.out.println("规则8触发了,全局变量的值为 = " + count);
        System.out.println("规则8触发了,全局变量list的值为 = " + list);
    end
// 设置全局变量
session.setGlobal("count",3000);
List<String> list = new ArrayList<>();
list.add("hahhah");
list.add("heehhhe");
session.setGlobal("list",list);

在这里插入图片描述

  1. query 查询符合条件的对象
query "query01"
    $order:OrderDTO(price == 100000)
end

query "query02"(Long prc)
    $order:OrderDTO(price == prc)
end
 // 创建Order对象
 OrderDTO dto = new OrderDTO();
 // 赋值测试数据
 dto.setPrice(new BigDecimal("10000"));
 OrderDTO dto2 = new OrderDTO();
 dto2.setPrice(new BigDecimal("100000"));
 // 将Order对象保存到工作内存当中
 session.insert(dto);
 session.insert(dto2);
 QueryResults results = session.getQueryResults("query01");
 QueryResults results2 = session.getQueryResults("query02",10000);
 System.out.println("results符合条件的个数 = "+results.size());
 System.out.println("results2符合条件的个数 = "+results2.size());

在这里插入图片描述
3. function 定义函数

function String sys(String name){
    return "自定义函数" + name;
}

rule "规则9、测试规则内置方法"
    when

    then
        String name = sys("规则9");
        System.out.println("规则9触发了 = " + name);
    end

在这里插入图片描述

  1. in / not in关键字
$order:OrderDTO(name in ("张三","李四","王武"))
$order:OrderDTO(name not in ("校长","老师","学生"))
  1. eval关键字 (放在LHS执行 如果是写true 则该规则执行 否则false 则不执行)
when
  eval(false)
  eval(true)
  eval(1 == 1)
then
  1. exists关键字 (判断工作内存中 指定的对象是否存在如果存在则返回true 规则执行 否则返回false 规则不执行)
exists OrderDTO()
exists OrderDTO(price == 100 && name != null)
  1. extends关键字 (作用是继承 如果父规则触发了那么子规则也会触发 所以两个规则必须同时满足才可以)
rule "规则10、测试高级语法"
    when
        exists OrderDTO(price == 100)
    then

    end

rule "规则11、测试高级语法" extends "规则10、测试高级语法"
    when
        // 需要注意的是 此时的规则条件是两个 一个是父规则的条件 + 子规则的条件
        exists OrderDTO(name != null)
    then
        System.out.println("规则10执行了");
    end
  1. halt方法 (当某一个规则调用了该方法 那么该规则下面所有的规则都不会执行 不管是否条件满足)
rule "规则12、测试高级语法"
    when

    then
        // 此时的12规则调用了halt 那么12下面的所有规则都不会在执行 不管规则是否满足
        drools.halt();
    end

ps:一只小菜鸟 一直在学习 从未敢停止


版权声明:本文为m0_45245077原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。