Drools规则引擎

news2024/11/28 23:39:18

Drools规则引擎

  • Drools规则引擎
  • 1、Drools简介
  • 2、Drools入门案例
    • 2.1、业务场景
    • 2.2、maven坐标
    • 2.3、编写xml配置文件(多方法)
    • 2.4、创建drl规则文件
    • 2.5、单元测试
  • 3、Drools基础语法
    • 3.1、规则文件的构成
    • 3.2、规则体语法结构
      • 3.2.1、条件部分
        • 3.2.1.1、约束连接
        • 3.2.1.2、比较操作符
      • 3.2.2、结果部分
        • 3.2.2.1、insert
        • 3.2.2.2、update
        • 3.2.2.3、retract
      • 3.2.3、属性部分
        • 3.2.3.1、salience
        • 3.2.3.2、no-loop
        • 3.2.3.3、date-effective
        • 3.2.3.4、date-expires
        • 3.2.3.5、enabled
        • 3.2.3.6、dialect
        • 3.2.3.7、activation-group
        • 3.2.3.8、agenda-group
        • 3.2.3.9、auto-focus
        • 3.2.3.10、timer
  • 4、高级语法
    • 4.1、global全局变量
    • 4.2、query查询
    • 4.3、function函数
  • 5、Springboot整合Drools
    • 5.1、添加maven依赖
    • 5.2、Drools配置类
    • 5.3、封装KieUtile静态规则容器实现规则热加载
    • 5.4、业务层使用规则引擎
  • 6、Drools WorkBench

Drools规则引擎

1、Drools简介

Drools(Drools Rule Engine)是一个开源的规则引擎,它主要用于在Java应用程序中实现规则管理。Drools规则引擎将规则定义和管理从应用程序代码中分离出来,使得规则可以独立于应用程序运行。这样可以提高规则的可靠性和可维护性,同时也可以使得规则的更新和管理更加方便。

Drools规则引擎的主要特点包括:

  1. 将规则定义和管理从应用程序代码中分离出来,使得规则可以独立于应用程序运行。
  2. 提供基于规则的访问和操作数据的功能,例如过滤、排序、检索等。
  3. 支持动态规则扩展和维护,可以根据需要添加、删除或修改规则。
  4. 规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则。
  5. 减少了硬编码业务规则的成本和风险。
  6. 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单。

Drools规则引擎在企业应用中被广泛应用,例如在电子商务、社交网络、移动应用等领域中,都可以使用Drools规则引擎来实现规则管理。

drools官网:[Drools - Drools - Business Rules Management System (Java™, Open Source)](https://www.drools.org/)

drools源码:GitHub - kiegroup/drools: Drools is a rule engine, DMN engine and complex event processing (CEP) engine for Java.

drools API开发步骤:获取KieServices => 获取KieContainer => kieSession => Insert fact => 触发规则 => 关闭KieSession

核心类关系

请添加图片描述

Kie全称为Knowledge ls Everything,即"知识就是一切"的缩写,是Jboss一系列项目的总称

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

  • Working Memory(工作内存)
  • Rule Base (规则库)
  • Inference Engine (推理引擎)

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

  • Pattern Matcher(匹配器)具体匹配哪一个规则,由这个完成
  • Agenda(议程)
  • Executior Engine (执行引擎)

2、Drools入门案例

2.1、业务场景

用户购买的金额和对应送多少积分的规则如下:

100元以下,不加分
100元-500元加100分
500元-1000元加500分
1000元以上加1000分

2.2、maven坐标

注意:不同版本可能有所不同,有些模块被单独拆分出来成为一个单独的模块,例如 drools-mvel 被从core单独拆分出来。

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

2.3、编写xml配置文件(多方法)

根据drools要求创建resources/META-INF/kmodule.xml配置文件
需要有一个配置文件告诉代码规则文件drl在哪里,在drools中这个文件就是kmodule.xml,放置到resources/META-INF目录下。

<?xml version="1.0" encoding="utf-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <!--
        name: kbase的名称
        packages: kbase下的package
        default: 默认的kbase
    -->
    <kbase name="rules" packages="droolsRule" default="true">
        <!--
            name: ksession的名称,需要唯一
            type: ksession的类型
            default: 默认的ksession
        -->
        <ksession name="rulesSession" default="true"/>
    </kbase>
</kmodule>

注意:上面配置文件的名称和位置都是固定写法,不能更改Kmodule 中可以包含一个到多个kbase,分别对应drl的规则文件。
Kbase 需要一个唯一的name,可以取任意字符串。
packages 为drl文件所在resource目录下的路径。注意区分drl文件中的package与此处的package不一定相同。多个包用逗号分隔。默认情况下会扫描resources目录下所有(包含子目录)规则文件。
kbase的default属性标示当前KieBase是不是默认的,如果是默认的则不用名称就可以查找到该KieBase,但每个module最多只能有一个默认KieBase。
kbase下面可以有一个或多个ksession, ksession的name 属性必须设置,且必须唯一。

2.4、创建drl规则文件

创建规则文件resources/droolsRule/rule1.drl

package rules;

import com.hippo.drools.entity.Order;


//100元以下,不加分
rule "score_1"
when
    $order:Order(price<100)
then
    $order.setScore($order.getScore()+0);
    System.out.println("触发了规则:100元以下,不加分");
end
//100元-500元加100分
rule "score_2"
when
    $order:Order(price>=100&&price<500)
then
    $order.setScore($order.getScore()+100);
    System.out.println("触发了规则:100元-500元加100分");
end
//500元-1000元加500分
rule "score_3"
when
    $order:Order(price>=500&&price<1000)
then
    $order.setScore($order.getScore()+500);
    System.out.println("触发了规则:500元-1000元加500分");
end
//1000元以上加1000分
rule "score_4"
when
    $order:Order(price>=1000)
then
    $order.setScore($order.getScore()+1000);
    System.out.println("触发了规则:1000元以上加1000分");
end

2.5、单元测试

创建Order实体

@Data
@AllArgsConstructor
@NoArgsConstructor
@Schema(name = "订单类")
public class Order {
    @Schema(name = "价格", example = "1")
    private Integer price;
    @Schema(name = "积分", example = "1")
    private Integer score;
}

创建测试类型

package com.hippo.provider;

import com.hippo.drools.entity.Order;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigDecimal;

/**
 * @ClassName DroolsTest
 * @Description TODO drools规则引擎单元测试
 * @Author tangxl
 * @create 2023-05-09 18:59
 **/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public class DroolsTest {
    @Test
    public void test(){
        // 第一步:初始化一个KieServices
        KieServices kieServices = KieServices.Factory.get();
        // 第二步:获取KieContainer会话对象
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 第三步:初始化KieSession
        KieSession kieSession = kieContainer.newKieSession();
        // 构造订单对象,设置订单价格,由规则引擎来计算订单积分
        Order order = new Order(500, 1);
        log.info("执行规则前的订单信息:{}",order);
        //第四步:将数据对象交给规则引擎,规则引擎根据提供的数据进行规则匹配
        kieSession.insert(order);

        // 第五步:激活规则引擎,如果符合规则执行规则
        kieSession.fireAllRules();
        // 第六步:关闭会话
        kieSession.dispose();
        // 结果打印
        log.info("执行规则后的订单信息:{}",order);
    }
}

执行输出结果

2023-05-10T09:57:16.723+08:00  INFO 13364 --- [           main] o.d.c.kie.builder.impl.KieContainerImpl  : Start creation of KieBase: myKbase1
2023-05-10T09:57:17.746+08:00  INFO 13364 --- [           main] o.d.c.kie.builder.impl.KieContainerImpl  : End creation of KieBase: myKbase1
2023-05-10T09:57:17.812+08:00  INFO 13364 --- [           main] com.hippo.provider.DroolsTest            : 执行规则前的订单信息:Order(price=500, score=1)
触发了规则:500元-1000元加500分
2023-05-10T09:57:17.864+08:00  INFO 13364 --- [           main] com.hippo.provider.DroolsTest            : 执行规则后的订单信息:Order(price=500, score=501)

3、Drools基础语法

3.1、规则文件的构成

drl是Drools Rule Language的缩写。

一套完整的规则文件内容构成如下:

  • package:包名,package对应的不一定是真正的目录,可以任意写com.rules,同一个包下的drl文件可以相互访问.
  • import:用于导入类或者静态方法
  • global:全局变量
  • function:自定义函数
  • query:查询
  • rule end:规则体

3.2、规则体语法结构

一个规则通常包括三个部分:属性部分(attribute)、条件部分(LHS)和结果部分(RHS)

rule "ruleName"		// rule关键字,表示规则开始,参数为规则的唯一名称
	attribute		// 规则属性,是rule与when之间的参数,为可选项
	when			// 关键字,后面是规则的条件部分
		LHS			// left Hand Side,是规则的条件部分
	then			// 后面跟规则的结果或行为
		RHS			// 是规则的结果或行为
end 				// 表示一个规则的结束

3.2.1、条件部分

LHS(Left Hand Side):是规则的条件部分的通用名称。它由零个或多个条件元素组成。如果LHS为空,则它将被视为始终为true的条件元素。

LHS部分由一个或多个条件组成,条件又称为pattern

pattern的语法结构:绑定变量名:Object(Filed约束)

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

//规则一:100元以下,不加分
rule "score_1"
when
	// 工作内存中必须存在Order这种类型的Fact对象----类型约束
    // Fact对象的price属性必须小于100----属性约束
    $order:Order(price<100)
then
    $order.setScore($order.getScore()+0);
    System.out.println("触发了规则:100元以下,不加分");
end

注:如果 LHS 为空,那么引擎会自动添加一个 eval(true) 的条件,由于该条件总是返回 true,所以 LHS 为空的规则总是返回 true.

3.2.1.1、约束连接

在 LHS 当中,可以包含 0~n 个条件,多个 pattern 之间可以采用 “&&”(and) 、 “lI”(or) 和 “,”(and) 来实现,也可以不写,默认连接为and。

//规则二:100元-500元加100分
rule "score_2"
when
    $order:Order(price>=100 && price<500)
then
    $order.setScore($order.getScore()+100);
    System.out.println("触发了规则:100元-500元加100分");
end

3.2.1.2、比较操作符

在Drools当中共提供了十二种类型的比较操作符,分别是: >、>=、<、<=、==、!=、contains、not contains、 memberof、not memberof、matches、not matches;在这十二种类型的比较操作符当中,前六个是比较常见也是用的比较多的比较操作符

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

案例:校验container是否包含order订单对象

第一步:创建Customer对象

package com.hippo.drools.fact;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;

/**
 * @ClassName Customer
 * @Description TODO 客户对象Fact
 * @Author tangxl
 * @create 2023-05-10 10:55
 **/
@Data
@Schema(name = "客户对象Fact")
public class Customer {
    @Schema(name = "客户ID", example = "1")
    private Integer id;

    @Schema(name = "客户名称", example = "张三")
    private String name;

    @Schema(name = "客户订单", example = "")
    private List<Order> orders;
}

第二步:新建drl文件

package rules.temprules;

import java.util.List;
import com.hippo.drools.fact.*;

rule "temprule11"
    when
        $order : Order()
        $customer : Customer( orders contains $order )
    then
        System.out.println( "触发规则:客户对象里面包含订单" );
    end

第三步:新建测试单元

    @Test
    public void test2(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();

        Order order = new Order(500, 1);
        Customer customer = new Customer();
        customer.setName("张三");
        customer.setOrders(Arrays.asList(order));

        kieSession.insert(order);
        kieSession.insert(customer);
        // RuleNameEndsWithAgendaFilter 用于过滤规则名称为temprule11的规则
//        kieSession.fireAllRules();
        kieSession.fireAllRules(new RuleNameEndsWithAgendaFilter("temprule11"));
        kieSession.dispose();
    }

结果一:未添加过滤器

16:42:31.425 [main] INFO org.drools.compiler.kie.builder.impl.InternalKieModuleProvider - Creating KieModule for artifact com.hippo:drools:0.0.1-SNAPSHOT
16:42:31.429 [main] DEBUG org.drools.compiler.kie.builder.impl.ClasspathKieProject - Discovered classpath module com.hippo:drools:0.0.1-SNAPSHOT
16:42:31.436 [main] DEBUG org.drools.compiler.kie.builder.impl.KieRepositoryImpl - KieModule was added: FileKieModule[releaseId=com.hippo:drools:0.0.1-SNAPSHOT,file=D:\Tools\SrcProject\learning\java-study\study-commons\drools\target\classes]
16:42:31.440 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
16:42:31.488 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:42:31.606 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:42:31.606 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:42:32.969 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
16:42:33.038 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:客户对象里面包含订单
触发了规则:500元-1000元加500分
16:42:33.093 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
16:42:33.093 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
16:42:33.093 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

结果二:添加过滤器 RuleNameEndsWithAgendaFilter 对规则名称进行过滤

16:39:53.563 [main] INFO org.drools.compiler.kie.builder.impl.InternalKieModuleProvider - Creating KieModule for artifact com.hippo:drools:0.0.1-SNAPSHOT
16:39:53.567 [main] DEBUG org.drools.compiler.kie.builder.impl.ClasspathKieProject - Discovered classpath module com.hippo:drools:0.0.1-SNAPSHOT
16:39:53.573 [main] DEBUG org.drools.compiler.kie.builder.impl.KieRepositoryImpl - KieModule was added: FileKieModule[releaseId=com.hippo:drools:0.0.1-SNAPSHOT,file=D:\Tools\SrcProject\learning\java-study\study-commons\drools\target\classes]
16:39:53.579 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
16:39:53.620 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:39:53.692 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:39:53.692 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
16:39:54.619 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
16:39:54.676 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:客户对象里面包含订单
16:39:54.720 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
16:39:54.720 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
16:39:54.720 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

注意:使用 contains 时,需要传入此 Fact 对象属性值里面需要校验 是否包含的对象 ,这里可以使用 RuleNameEndsWithAgendaFilter 等过滤器对规则名称进行限制,不让传入 校验是否包含的对象 也进行一次规则校验。

3.2.2、结果部分

在Drools当中,在RHS里面,提供了一些对当前Working Memory 实现快速操作的宏宏函数或对象,比如 insert/insertLogical、update 和 retract 就可以实现对当前 Working Memory 中的 Fact 对象进行新增、删除或者是修改。

3.2.2.1、insert

函数 insert 的作用与我们在Java类当中调用 StatefulKnowledgeSession 对象的 insert 方法的作用相同,都是用来将一个 Fact 对象插入到当前的 Working Memory 当中
注意:一旦调用 insert 宏函数,那么 Drools 会重新与所有的规则再重新匹配一次,对于没有设置 no-loop 属性为 true 的规则,如果条件满足,不管其之前是否执行过都会再执行一次,这个特性不仅存在于 insert 宏函数上,后面介绍的 update、retract 宏函数同样具有该特性,所以在某些情况下因考虑不周调用 insert、update 或 retract 容易发生死循环

示例:

添加规则

rule "temprule2"
    when
     eval( true ) // 为了测试,这里写死了都需要执行
    then
        Customer customer = new Customer();
        customer.setName( "张三" );
        Order order = new Order( 500,10 );
        customer.setOrders( Arrays.asList(order));
        insert(customer);
        System.out.println( "触发规则:插入客户对象" );
end

单元测试

    @Test
    public void test3(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.fireAllRules();
        kieSession.dispose();
    }

结果

17:02:36.791 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
17:02:36.821 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:02:36.880 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:02:36.880 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:02:37.649 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
17:02:37.704 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:插入客户对象
触发规则:客户对象里面包含订单
触发了规则:500元-1000元加500分
17:02:37.734 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
17:02:37.734 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
17:02:37.735 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

总结:在规则中插入了一个客户 Fact 对象和一个订单 Fact 对象结果触发了上一面演示的比较符的规则,说明在规则中插入的 Fact 对象会重新去一遍满足条件的规则,注意避免死循环。

insertLogical
insertLogical作用与insert类似,它的作用也是将一个Fact对象插入到当前的 Working Memroy当中。

3.2.2.2、update

update 与 insert 类型,用来实现对当前 Working Memory 当中的 Fact 进行更新,用来告诉当前 Working Memory 该 Fact 对象已经发生了该变。

示例:

添加规则

rule "temprule3"
    when
        $customer : Customer( name == "张三" )
    then
        $customer.setName("李四");
        update($customer);
        System.out.println( "触发规则:更新Fact对象" );
end

rule "temprule4"
    when
        $customer : Customer( name == "李四" )
    then
        System.out.println( "触发规则:"+$customer.getName());
end

单元测试

    @Test
    public void test4(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();

        Customer customer = new Customer();
        customer.setName("张三");
        System.out.println("修改前的客户名对象:" + customer);
        kieSession.insert(customer);

        kieSession.fireAllRules();
        kieSession.dispose();
        System.out.println("修改后的客户名对象:" + customer);
    }

输出结果

17:27:36.738 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
17:27:36.772 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:27:36.840 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:27:36.840 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
17:27:37.613 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
修改前的客户名对象:Customer(id=null, name=张三, orders=null)
17:27:37.663 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:更新Fact对象
触发规则:李四
17:27:37.696 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
17:27:37.697 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
17:27:37.697 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
修改后的客户名对象:Customer(id=null, name=李四, orders=null)

总结:在规则中更新了一个客户 Fact 对象触发了另一个规则,说明在规则中更新的 Fact 对象会重新去一遍满足条件的规则,注意避免死循环。

**规则属性 no-loop true **:插入、更新了 Fact 对象不会本规则、方法、函数只会调用一次,不会再去重复调用

rule "temprule9"
    no-loop
    when
        $customer : Customer( name == "王五" )
    then
        $customer.setName("王五");
        update($customer);
        System.out.println( "触发规则:temprule9" );
end

3.2.2.3、retract

retract 用来将 Working Memory 当中某个 Fact 对象从 Working Memory 当中删除

示例:

添加规则

rule "temprule3"
    when
        $customer : Customer( name == "张三" )
    then
        $customer.setName("李四");
        update($customer);
        System.out.println( "触发规则:更新Fact对象" );
end

rule "temprule4"
    when
        $customer : Customer( name == "李四" )
    then
        System.out.println( "触发规则:"+$customer.getName());
end

单元测试

    /**
     * 测试Drools内置方法retract:删除对象
     */
    @Test
    public void test5(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();

        Customer customer = new Customer();
        customer.setName("李四");
        System.out.println("修改前的客户名对象:" + customer);
        kieSession.insert(customer);

        kieSession.fireAllRules();
        kieSession.dispose();
        System.out.println("修改后的客户名对象:" + customer);
    }

输出结果

122:26:04.360 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
22:26:04.376 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:26:04.421 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:26:04.422 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:26:04.888 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
修改前的客户名对象:Customer(id=null, name=李四, orders=null)
22:26:04.919 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
Drools规则内置方法retract删除Fact对象触发
22:26:04.941 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
22:26:04.941 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
22:26:04.941 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
修改后的客户名对象:Customer(id=null, name=李四, orders=null)

总结:调用 retract 方法后 Working Memory 中的对象被删除了,不能进一步匹配其他规则了,但是传递进去那个地址的对象还没有删除

3.2.3、属性部分

Drools提供的属性表:

属性名说明
salience定义规则优先级,是一个整数。当在激活队列中排序时salience的值越大,优先级越高
dialect指定规则使用的语言类型,取值为java和mvel
enabled定义规则是否启用,true 启用,false 禁用,默认值是true
date-effective包含时间和日期的字符串,当当前时间大于date-effective时,该规则才会被激活。这个时间格式可以修改,见下方具体的用法
date-expires设置规则的过期时间,时间格式和上方一样。
activation-group表示该组下的规则只有一个规则会被执行,该组下其余激活的规则会被取消执行。 但是别的组激活的规则可能会被执行。
agenda-groupAgenda groups允许您对agenda进行分区,以提供对规则组的更多执行控制。 只有获得焦点的议程组中的规则才能被激活 ,但是这个里面有个特例,如果某个规则没有配置 agenda-group,但是它模式匹配成功了,那么会被分到默认的组(main),这个main组的规则也会执行。
timer一个字符串,标识用于调度规则的 int(间隔)或 cron 计时器定义。
auto-focus布尔值,仅适用于Agenda-Group内的规则。当值为true时,下次激活该规则时,会将焦点自动给这个Agenda group
no-loop布尔值,默认值为false, 定义当当前规则规则的结果修改了fact对象时,是否可以再次执行该规则。true:不可以, false:可以,可能会导致死循环。指的是当前规则的修改,如果别的规则修改了,还会导致该规则的触发防止死循环
durationlong类型的值,如果在这个时间之后规则还成立,那么执行该规则
calendar定义Quartz calendar用于调度规则。
lock-on-active一个布尔值,仅适用于规则流组或议程组中的规则。 选择该选项后,下次规则的规则流组变为活动状态或规则的议程组获得焦点时,规则无法再次激活,直到规则流组不再处于活动状态或议程组失去焦点。 这是 no-loop 属性的更强版本,因为匹配规则的激活被丢弃,无论更新的来源如何(不仅是规则本身)。 此属性非常适合计算规则,其中您有许多修改事实的规则并且您不希望任何规则重新匹配和再次触发。

3.2.3.1、salience

作用是用来设置规则执行的优先级,salience属性的值是一个数字,数字越大执行优先级越高。默认情况下,规则的salience默认值为0。如果不设置sJience属性,规则体的执行顺序为由上到下。

示例:

添加规则

rule "temprule7"
    salience 1
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule7");
end

rule "temprule8"
    salience 2
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule8");
end

单元测试

    /**
     * 测试Drools属性sailence:设置的数字越大,优先级越高
     */
    @Test
    public void test6(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.fireAllRules();
        kieSession.dispose();
    }

输出结果

22:38:24.726 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
22:38:24.741 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:38:24.780 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:38:24.780 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:38:25.294 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
22:38:25.325 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:temprule8
触发规则:temprule7
22:38:25.335 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
22:38:25.335 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
22:38:25.335 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

总结:不添加 salience 属性,默认 salience 值为 0 从上到下开始执行规则,添加了 salience 属性,根据他的值从大到小开始执行

3.2.3.2、no-loop

作用是用来控制已经执行过的规则在条件再次满足时是否再次执行。no-loop 属性的值是一个布尔型,默认情况下规则的 no-loop 属性的值为 false,如果no-loop属性值为 true,那么就表示该规则只会被引擎检查一次,如果满足条件就执行规则的 RHS 部分,如果引擎内部因为对Fact更新引起引擎再次启动检查规则,那么它会忽略掉所有的 no-loop属性设置为true 的规则。

示例:

添加规则

rule "temprule9"
    no-loop
    when
        $customer : Customer( name == "王五" )
    then
        $customer.setName("王五");
        update($customer);
        System.out.println( "触发规则:temprule9" );
end

单元测试

    /**
     * 测试Drools属性no-loop:防止规则出现循环调用
     */
    @Test
    public void test7(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();

        Customer customer = new Customer();
        customer.setName("王五");

        kieSession.insert(customer);
        kieSession.fireAllRules();
        kieSession.dispose();
    }

输出结果

22:46:28.384 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
22:46:28.398 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:46:28.443 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:46:28.443 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
22:46:28.911 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
22:46:28.937 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:temprule9
22:46:28.955 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
22:46:28.955 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
22:46:28.955 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

总结:当插入、更新操作 Fact 对象时,会从新扫描所有符合规则的去执行,设置 no-loop 属性为 true,规则就只会被加载一次

3.2.3.3、date-effective

作用是用来控制规则只有在到达后才会触发,在规则运行时,引擎会自动拿当前操作系统的时候与date-effective设置的时间值进行比对,只有当系统时间>=date-efective设置的时间值时,规则才会触发执行,否则执行将不执行。在没有设置该属性的情况下,规则随时可以触发,没有这种限制。date-effective的值为一个日期型的字符串,默认情况下 date-effective 可接受的日期格式为 “dd-MMM-yyyy” ,例:date-effective “1-5月-2023”

在实际使用的过程当中,如果您不想用这种时间的格式,那么可以在调用的Java代码中通过使用 System.setProperty(Stringkey,String value) 方法来修改默认的时间格式
在java文件中添加此条命令: System.setProperty(“drools.dateformat”,“yyyy-MM-dd”);

示例:

添加规则

rule "temprule10"
//    date-effective "1-5月-2023" // 默认时间格式:当前时间大于等于2023-05-01时,规则才会生效
    date-effective "2023-05-01" // 自定义时间格式:当前时间大于等于2023-05-01时,规则才会生效
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule10" );
end

单元测试

    /**
     * 测试Drools属性date-effective:设置规则生效时间,默认时间格式为:dd-MMM-yyyy,例如:10-八月-2021
     */
    @Test
    public void test8(){
        // 设置日期格式,否则可能会报错(Wrong date-effective value: Invalid date input format: [2022-05-18 10:54:26] it should follow: [d-MMM-yyyy]]])
        System.setProperty("drools.dateformat", "yyyy-MM-dd");
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        // 只匹配规则名称是已 temprule10 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("temprule"));
        kieSession.dispose();
    }

输出结果

23:03:37.862 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
23:03:37.876 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:03:37.916 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:03:37.916 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:03:38.414 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
23:03:38.447 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:temprule10
23:03:38.454 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
23:03:38.454 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
23:03:38.454 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

总结:注意设置日期格式,否则可能会报错(Wrong date-effective value: Invalid date input format: [2022-05-18 10:54:26] it should follow: [d-MMM-yyyy]]])

3.2.3.4、date-expires

作用是与date-effective属性恰恰相反,date-expires的作用是用来设置规则的有效期,引擎在执行规则的时候,会检查规则有没有date-expires属性,如果有的话,那么会将这个属性的值与当前系统时间进行比对,如果大于系统时间,那么规则就执行,否则就不执行。和date-effective的用法类似,此处就不演示了。

3.2.3.5、enabled

作用是用来定义一个规则是否可用的。该属性的值是一个布尔值,默认该属性的值为true,表示规则是可用的。设置其enabled属性值为false,那么引擎就不会执行该规则

3.2.3.6、dialect

作用是用来定义规则当中要使用的语言类型,目前支持两种类型的语言: mvel 和 java ,默认情况下,如果没有手工设置规则的 dialect ,那么使用的 java 语言

3.2.3.7、activation-group

作用是将若干个规则划分成一个组,用一个字符串来给这个组命名,这样在执行的时候,具有相同activation-group属性的规则中只要有一个会被执行,其它的规则都将不再执行。
也就是说,在一组具有相同activation-group属性的规则当中,只有一个规则会被执行,其它规则都将不会被执行。当然对于具有相同activation-group属性的规则当中究竟哪一个会先执行,则可以用类似salience之类属性来实现。

示例:

添加规则

rule "temprule11"
    activation-group "test"
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule11" );
end

rule "temprule12"
    activation-group "test"
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule12" );
end

单元测试

    /**
     * 测试Drools属性activation-group:激活分组,每次只能激活一个分组
     */
    @Test
    public void test9(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        // 只匹配规则名称是已 temprule 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("temprule"));
        kieSession.dispose();
    }

输出结果

23:13:45.598 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
23:13:45.611 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:13:45.642 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:13:45.642 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:13:46.082 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
23:13:46.113 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:temprule11
23:13:46.122 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
23:13:46.122 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
23:13:46.122 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED
Disconnected from the target VM, address: '127.0.0.1:62864', transport: 'socket'

Process finished with exit code 0

总结:同一个分组,只有一个规则会被执行,都符合的规则会根据属性 salience 的值去决定执行哪一个

3.2.3.8、agenda-group

作用是 agenda-group 属性的值也是一个字符串,通过这个字符串,可以将规则分为若干个 Agenda Group ,默认情况下,引擎在调用这些设置了 agenda-group 属性的规则的时候需要显示的指定某个 Agenda Group 得到 Focus (焦点),这样位于该 Aaenda Group 当中的规则才会触发执行,否则将不执行。

示例:

添加规则

rule "temprule13"
    agenda-group "group1"
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule13" );
end

rule "temprule14"
    agenda-group "group2"
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule14" );
end

单元测试

/**
     * 测试Drools属性agenda-group: Agenda groups 允许您对 agenda 进行分区,以提供对规则组的更多执行控制。
     * 只有获得焦点的议程组中的规则才能被激活。但是这个里面有个特例,如果某个规则没有配置 agenda-group,
     * 但是它模式匹配成功了,那么会被分到默认的组(main),这个 main 组的规则也会执行。
     */
    @Test
    public void test10(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.getAgenda().getAgendaGroup("group1").setFocus();
        // 只匹配规则名称是已 temprule 开头的规则,忽略其余的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("temprule"));
        kieSession.dispose();
    }

输出结果

23:22:15.856 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
23:22:15.871 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:22:15.907 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:22:15.907 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:22:16.394 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
23:22:16.425 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
触发规则:temprule13
23:22:16.433 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
23:22:16.433 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
23:22:16.433 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

总结:没有设置 Focus 焦点,都不会执行。

3.2.3.9、auto-focus

作用是用来在已设置了 agenda-group 的规则上设置该规则是否可以自动独取 Focus,如果该属性设置为 true ,那么在引擎执行时,就不需要显示的为某个 Agenda Group 设置 Focus,否则需要。

3.2.3.10、timer

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

方式一
此种方式遵循java.util.Timer对象的使用方式,第一个参数表示几秒后执行,第二个参数表示每隔几秒执行一次,第二个参数为可选。

方式二
此种方式使用标准的unix cron表达式的使用方式来定义规则执行的时间。

示例:

添加规则

rule "temprule14" // 方式一
    timer (5s 2s) // 5秒后执行,每2秒执行一次
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule14,触发时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) );
end

rule "temprule15" // 方式二
    timer (cron: 0/5 * * * * ?) // 每5秒执行一次
    when
        eval( true ) // 为了测试,这里写死了都需要执行
    then
        System.out.println( "触发规则:temprule15,触发时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) );
end

单元测试

    /**
     * 测试Drools属性timer: 规则定时器,规则在指定时间后执行
     */
    @Test
    public void test11(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        new Thread(() -> {
            // 等待20秒
            kieSession.fireUntilHalt();
        }).start();
        try {
            // 等待10秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 停止执行
        kieSession.halt();
        kieSession.dispose();
    }

输出结果

23:39:38.977 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
23:39:38.991 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:39:39.025 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:39:39.025 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
23:39:39.482 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
23:39:39.516 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_UNTIL_HALT
23:39:39.534 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:40.003 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now FIRING_UNTIL_HALT
触发规则:rule_time_2,触发时间:2023-05-10 23:39:40
23:39:40.005 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:44.532 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now FIRING_UNTIL_HALT
触发规则:rule_time_1,触发时间:2023-05-10 23:39:44
23:39:44.534 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:45.001 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now FIRING_UNTIL_HALT
触发规则:rule_time_2,触发时间:2023-05-10 23:39:45
23:39:45.001 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:46.528 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now FIRING_UNTIL_HALT
触发规则:rule_time_1,触发时间:2023-05-10 23:39:46
23:39:46.528 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:48.528 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now FIRING_UNTIL_HALT
触发规则:rule_time_1,触发时间:2023-05-10 23:39:48
23:39:48.529 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_UNTIL_HALT is now INACTIVE_ON_FIRING_UNTIL_HALT
23:39:49.519 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE_ON_FIRING_UNTIL_HALT is now DISPOSED
23:39:49.519 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was DISPOSED is now FIRING_UNTIL_HALT
23:39:49.519 [Thread-0] DEBUG org.drools.core.common.DefaultAgenda - State was DISPOSED is now INACTIVE

4、高级语法

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

4.1、global全局变量

全局变量,一般用作执行规则后的结果数据返回或对具体某个服务调用等,如一个电子邮件服务的实例,在调用规则引擎的集成代码中,获取emailService对象,然后将其设置在工作内存中。

语法结构为: global 对象类型 对象名称

示例:

添加规则

package rules.temprules;

import java.util.List;

global java.util.List myGlobalList; //如果规则文件中有global关键字,那么在执行规则文件时,必须要设置global变量的值,否则会报错

/**
* @Description: Drools高级语法
*/
rule "global_rule1"
    when
        eval(true) //eval语法,可以在规则文件中执行java代码
    then
        myGlobalList.add("global_rule1"); //在规则文件中,可以直接调用global变量
        System.out.println("global_rule1规则被触发");
end

rule "global_rule2"
    when
        eval(true) //eval语法,可以在规则文件中执行java代码
    then
        System.out.println("myGlobalList的元素个数:" + myGlobalList.size());
        System.out.println("global_rule2规则被触发");
end

单元测试

 @Test
    public void test1(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        // 设置一个全局变量,名称必须与规则文件中的全局变量名称一致
        List<String> list = new ArrayList<>();
        kieSession.setGlobal("myGlobalList", list);
        // 执行以global_rule开头的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("global_rule"));
        kieSession.dispose();
    }

输出结果

10:05:08.071 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
10:05:08.102 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:05:08.165 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:05:08.165 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:05:09.011 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
10:05:09.070 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
global_rule1规则被触发
myGlobalList的元素个数:1
global_rule2规则被触发
10:05:09.096 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
10:05:09.096 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
10:05:09.096 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

4.2、query查询

query语法提供了一种查询working memory中符合约束条件的 FACT 对象的简单方法。它仅包含规则文件中的 LHS 部分,不用指定 “when” 和 “then” 部分。Query有一个可选参数集合,每一个参数都有可选的类型。如果没有指定类型,则默认为 Object 类型。引擎会尝试强转为需要的类型。对于 KieBase 来说,query 的名字是全局性的,因此不要向同一 RuleBase 的不同包添加相同名称的query 。
使用 ksession.getQueryResults(“name”) 方法可以获得查询的结果,其中 name 为 query 的名称,方法的返回结果一个列表,从中可以获取匹配查询到的对象。

示例:

新建Persion类

package com.hippo.drools.fact;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @ClassName Persion
 * @Description TODO 人规则类
 * @Author tangxl
 * @create 2023-05-11 10:15
 **/
@Data
@Schema(description = "人")
@AllArgsConstructor
@NoArgsConstructor
public class Persion {
    @Schema(description = "主键ID",example = "1")
    private Integer id;
    @Schema(description = "姓名",example = "张三")
    private String name;
    @Schema(description = "年龄",example = "18")
    private Integer age;
}

添加规则

// 不带参数的query语法
// 当前query用于查询 WorkingMemory 中age大于20的Persion对象
query "query_rule1"
   $persion : Persion(age > 20)
end

// 带参数的query语法
// 当前query用于查询 WorkingMemory 中age大于20并且name等于nameParam的Persion对象
query "query_rule2"(String nameParam)
   $persion : Persion(age > 20,name == nameParam)
end

单元测试

/**
     * 测试query查询:query关键字用于声明查询,查询可以在规则文件中使用,也可以在java代码中使用
     */
    @Test
    public void test2(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession();
        // 插入 Persion 对象
        kieSession.insert(new Persion(1,"张三",18));
        kieSession.insert(new Persion(2,"李四",20));
        kieSession.insert(new Persion(3,"王五",22));

        // 执行以querye开头的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("query"));
        // 不带参数查询
        QueryResults result1 =  kieSession.getQueryResults("query1");
        for (QueryResultsRow row : result1) {
            Persion persion = (Persion) row.get("$persion");
            System.out.println("不带参数查询结果:"+persion);
        }
        QueryResults result2 =  kieSession.getQueryResults("query2","王五");
        for (QueryResultsRow row : result2) {
            Persion persion = (Persion) row.get("$persion");
            System.out.println("带参数查询结果:"+persion);
        }

        kieSession.dispose();
    }

输出结果

10:32:24.083 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
10:32:24.112 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:32:24.171 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:32:24.171 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:32:25.051 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
10:32:25.110 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
10:32:25.152 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
10:32:25.153 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
10:32:25.153 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.153 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
10:32:25.153 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.153 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
10:32:25.155 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.156 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
不带参数查询结果:Persion(id=2, name=李四, age=20)
不带参数查询结果:Persion(id=3, name=王五, age=22)
10:32:25.158 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.158 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
10:32:25.158 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.159 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
10:32:25.159 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now EXECUTING_TASK
10:32:25.162 [main] DEBUG org.drools.core.common.DefaultAgenda - State was EXECUTING_TASK is now INACTIVE
带参数查询结果:Persion(id=3, name=王五, age=22)
10:32:25.163 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

4.3、function函数

在规则中可以通过函数来做一些通用的逻辑,就相当于java类中的方法一样。

示例

function String getFunctionName(String name){
    return "function_" + name;
}

函数返回类型与参数类型与java的规则一样

测试示例

添加规则

// function 语法测试
rule "function_rule1"
    when
        eval(true) //eval语法,可以在规则文件中执行java代码
    then
        System.out.println("function_rule1规则被触发");
        System.out.println("function_rule1规则中调用function:" + getFunctionName("function_rule1"));
end

单元测试

    /**
     * 测试function函数:function关键字用于声明函数,函数可以在规则文件中使用,也可以在java代码中使用
     */
    @Test
    public void test3(){
        KieServices kieServices = KieServices.Factory.get();
        KieContainer kieContainer = kieServices.getKieClasspathContainer();
        // 获取KieSession
        KieSession kieSession = kieContainer.newKieSession();
        // 执行以function_rule开头的规则
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter("function_rule"));
        kieSession.dispose();
    }

输出结果

10:39:22.880 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - Start creation of KieBase: myKbase1
10:39:22.934 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:39:23.039 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:39:23.039 [main] DEBUG org.drools.compiler.compiler.JavaDialectConfiguration - Selected compiler ECLIPSE [drools.dialect.java.compiler:null, hasEclipseCompiler:true]
10:39:24.265 [main] INFO org.drools.compiler.kie.builder.impl.KieContainerImpl - End creation of KieBase: myKbase1
10:39:24.332 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now FIRING_ALL_RULES
function_rule1规则被触发
function_rule1规则中调用function:function_function_rule1
10:39:24.367 [main] DEBUG org.drools.core.common.DefaultAgenda - State was FIRING_ALL_RULES is now HALTING
10:39:24.368 [main] DEBUG org.drools.core.common.DefaultAgenda - State was HALTING is now INACTIVE
10:39:24.368 [main] DEBUG org.drools.core.common.DefaultAgenda - State was INACTIVE is now DISPOSED

5、Springboot整合Drools

5.1、添加maven依赖

 		<!--drools规则引擎相关依赖-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-core</artifactId>
        </dependency>
        <!-- 低版本:mvel集成在drools-core中 高版本:mvel被单独拆分出来-->
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-mvel</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-templates</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-api</artifactId>
            <version>7.73.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.kie</groupId>
            <artifactId>kie-spring</artifactId>
            <version>7.73.0.Final</version>
        </dependency>

5.2、Drools配置类

package com.hippo.drools.utils;

import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

import static com.hippo.drools.config.RuleEngineConfig.BASE_RULES_PATH;
import static com.hippo.drools.config.RuleEngineConfig.RULES_PATH;

/**
 * @ClassName KieUtils
 * @Description TODO 热加载,需要重载规则文件,规则引擎容器要支持变动
 * @Author tangxl
 * @create 2023-05-08 10:23
 **/
@Slf4j
public class KieUtils {
    /**
     * 规则引擎容器
     */
    private static KieContainer kieContainer;

    /**
     * 规则引擎会话
     */
    private static KieSession kieSession;

    /**
     * 规则引擎容器后置处理器
     */
    private static KModuleBeanFactoryPostProcessor kModuleBeanFactoryPostProcessor;

    /**
     * 读取规则文件,并将规则文件写入到规则引擎系统内
     * @return
     * @throws IOException
     * @return
     */
    public static KieContainer getKieContainer() {
        return kieContainer;
    }

    /**
     * 设置规则引擎容器
     * @param kieContainer
     */
    public static void setKieContainer(KieContainer kieContainer) {
        KieUtils.kieContainer = kieContainer;
        kieSession = kieContainer.newKieSession();
    }

    /**
     * 获取规则引擎会话
     * @return
     */
    public static KieSession getKieSession() {
        return kieSession;
    }

    /**
     * 设置规则引擎会话
     * @param kieSession
     */
    public static void setKieSession(KieSession kieSession) {
        KieUtils.kieSession = kieSession;
    }

    /**
     * 获取规则文件
     * @return
     */
    public static KieServices getKieServices() {
        return KieServices.Factory.get();
    }

    /**
     * 获取初始化规则文件所在路径
     * @return
     */
    public static KModuleBeanFactoryPostProcessor getkModuleBeanFactoryPostProcessor() {
        return kModuleBeanFactoryPostProcessor;
    }

    /**
     * 设置规则引擎容器后置处理器
     * @param kModuleBeanFactoryPostProcessor
     */
    public static void setkModuleBeanFactoryPostProcessor(KModuleBeanFactoryPostProcessor kModuleBeanFactoryPostProcessor) {
        KieUtils.kModuleBeanFactoryPostProcessor = kModuleBeanFactoryPostProcessor;
    }

    public static void main(String[] args) throws IOException {
        // 获取初始化规则文件所在路径
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] files = resourcePatternResolver.getResources(BASE_RULES_PATH + RULES_PATH + "*.*");
        System.out.println(files.length);
    }
}

5.3、封装KieUtile静态规则容器实现规则热加载

package com.hippo.drools.utils;

import lombok.extern.slf4j.Slf4j;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.spring.KModuleBeanFactoryPostProcessor;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.IOException;

import static com.hippo.drools.config.RuleEngineConfig.BASE_RULES_PATH;
import static com.hippo.drools.config.RuleEngineConfig.RULES_PATH;

/**
 * @ClassName KieUtils
 * @Description TODO 热加载,需要重载规则文件,规则引擎容器要支持变动
 * @Author tangxl
 * @create 2023-05-08 10:23
 **/
@Slf4j
public class KieUtils {
    /**
     * 规则引擎容器
     */
    private static KieContainer kieContainer;

    /**
     * 规则引擎会话
     */
    private static KieSession kieSession;

    /**
     * 规则引擎容器后置处理器
     */
    private static KModuleBeanFactoryPostProcessor kModuleBeanFactoryPostProcessor;

    /**
     * 读取规则文件,并将规则文件写入到规则引擎系统内
     * @return
     * @throws IOException
     * @return
     */
    public static KieContainer getKieContainer() {
        return kieContainer;
    }

    /**
     * 设置规则引擎容器
     * @param kieContainer
     */
    public static void setKieContainer(KieContainer kieContainer) {
        KieUtils.kieContainer = kieContainer;
        kieSession = kieContainer.newKieSession();
    }

    /**
     * 获取规则引擎会话
     * @return
     */
    public static KieSession getKieSession() {
        return kieSession;
    }

    /**
     * 设置规则引擎会话
     * @param kieSession
     */
    public static void setKieSession(KieSession kieSession) {
        KieUtils.kieSession = kieSession;
    }

    /**
     * 获取规则文件
     * @return
     */
    public static KieServices getKieServices() {
        return KieServices.Factory.get();
    }

    /**
     * 获取初始化规则文件所在路径
     * @return
     */
    public static KModuleBeanFactoryPostProcessor getkModuleBeanFactoryPostProcessor() {
        return kModuleBeanFactoryPostProcessor;
    }

    /**
     * 设置规则引擎容器后置处理器
     * @param kModuleBeanFactoryPostProcessor
     */
    public static void setkModuleBeanFactoryPostProcessor(KModuleBeanFactoryPostProcessor kModuleBeanFactoryPostProcessor) {
        KieUtils.kModuleBeanFactoryPostProcessor = kModuleBeanFactoryPostProcessor;
    }

    public static void main(String[] args) throws IOException {
        // 获取初始化规则文件所在路径
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource[] files = resourcePatternResolver.getResources(BASE_RULES_PATH + RULES_PATH + "*.*");
        System.out.println(files.length);
    }
}
package com.hippo.drools.service.impl;

import com.hippo.drools.config.RuleEngineConfig;
import com.hippo.drools.utils.KieUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;

import java.io.IOException;

/**
 * @ClassName ReloadDroolsRulesServiceImpl
 * @Description TODO 重载规则引擎的规则
 * @Author tangxl
 * @create 2023-05-08 10:49
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class ReloadDroolsRules {
    /**
     * 规则引擎会话
     */
    private final KieSession kieSesion;
    /**
     * 规则引擎容器
     */
    private final KieContainer kieContainer;

    /**
     * 重载规则引擎的规则
     * @param drlName 规则文件名
     */
    public void reload(String drlName) {
        log.info("开始重载规则引擎的规则");
        // 获取规则引擎的文件系统
        KieFileSystem kfs = KieUtils.getKieServices().newKieFileSystem();
        loadFileRules(drlName, kfs);
        kieContainer.updateToVersion(kieContainer.getReleaseId());
        log.info("重载规则引擎的规则结束");
    }

    /**
     * 重新配置规则文件
     * @param drlName 规则文件名
     * @param kfs 规则引擎的文件系统
     */
    private void loadFileRules(String drlName, KieFileSystem kfs) {
        String path = "../../study-commons/drools/src/main/resources/" + RuleEngineConfig.RULES_PATH + drlName + ".drl";
        // 从数据库加载的规则
        kfs.write(path, "\"package plausibcheck.adress\\n\\n import com.leopard.drools.pojo.QueryParam;\\n\\n rule \\\"Postcode 6 numbers\\\"\\n\\n    when\\n  then\\n        System.out.println(\\\"打印日志:更新rules成功!\\\");\\n end\"");
    }

    private Resource[] getRuleFiles(String drlName) throws IOException {
        if (StringUtils.isEmpty(drlName)) {
            ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
            return resourcePatternResolver.getResources(RuleEngineConfig.BASE_RULES_PATH + RuleEngineConfig.RULES_PATH + "**/*.*");
        }
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        return resourcePatternResolver.getResources(RuleEngineConfig.BASE_RULES_PATH + RuleEngineConfig.RULES_PATH + "**/" + drlName + ".*");
    }

}

5.4、业务层使用规则引擎

package com.hippo.provider.service.impl;

import com.hippo.core.pojo.entity.WarnRuleDetail;
import com.hippo.core.pojo.vo.result.BaseResult;
import com.hippo.provider.service.WarningRuleService;
import lombok.RequiredArgsConstructor;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Service;

/**
 * @ClassName WarningRuleServiceImpl
 * @Description TODO 预警规则业务处理
 * @Author tangxl
 * @create 2023-05-11 11:40
 **/
@Service
@RequiredArgsConstructor
public class WarningRuleServiceImpl implements WarningRuleService {
    /**
     * 规则引擎容器
     */
    private final KieBase kieBase;

    /**
     * 预警规则校验
     * @return
     */
    @Override
    public BaseResult warnRuleCheck(WarnRuleDetail warnRuleDetail) {
        KieSession kieSession = kieBase.newKieSession();
        kieSession.insert(warnRuleDetail);
        kieSession.fireAllRules();
        kieSession.dispose();
        return BaseResult.ok(warnRuleDetail);
    }
}

6、Drools WorkBench

它是一个可视化的规则编辑器。WorkBench其实就是一个war包,安装到tomcat中就可以运行。使用WorkBench可以在浏览器中创建数据对象、创建规则文件、创建测试场景并将规则部署到maven仓库供其他应用使用。

下载地址:Index of /drools/release (jboss.org)

注意:选择自己需要的版本,与依赖中的版本相对应,新版的workbench 已经不支持Tomcat部署了,需要使用wildfly部署。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/590173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day4,day5 -java集合框架

List、Set、Map等常用集合类的特点和用法。 常用集合类&#xff08;List、Set、Map 等&#xff09;是 Java 中提供的数据结构&#xff0c;用于存储和操作一组数据。以下是它们的特点和用法&#xff1a; List&#xff08;列表&#xff09;: 特点&#xff1a;有序集合&#xff0…

多元办公场景下,企业如何保障工作效率与数据安全流通?

为适应数字化转型需求&#xff0c;提升办公效率&#xff0c;很多企业对工作模式进行革新&#xff0c;并将更多协同办公工具引入工作流程。然而&#xff0c;这也扩大了企业内网对外的安全暴露面&#xff0c;企业亟需进一步加强底层基础设施的网络安全建设&#xff0c;严防勒索病…

分布式监控平台——Zabbix6.0

市场上常用的监控软件&#xff1a; 传统运维&#xff1a;zabbix、 Nagios云原生环境&#xff1a; Prometheus &#xff08;go语言开发的&#xff09; 一、zabbix概述 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数…

内网渗透(八十六)之Exchange ProxyLogon攻击链利用

Exchange ProxyLogon攻击链利用 漏洞背景 2021年3月2日,微软发布了Exchange服务器的紧急安全更新,修复了如下7个相关的漏洞。 Exchange服务端请求伪造漏洞(CVE-2021-26855):未经身份验证的攻击者能够构造HTTP请求扫描内网并通过Exchange服务器进行身份验证。Exchange反序列…

基于SpringBoot的财务管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;…

王石创立“生物圈三号”发起“双碳同行者大会”,绿色家居企业参与其中

2023年5月27日 &#xff0c;由万科集团创始人、深石集团创始人王石先生创立的碳中和社区品牌“生物圈三号”在深圳大梅沙成功举办了“回归未来双碳同行——生物圈三号双碳同行者大会暨全球运河穿越新书发布会”。 生物圈三号作为社区碳中和综合解决方案平台&#xff0c;为建筑、…

JVM-基础知识

JVM基础知识 JVM结构图 字节码文件 Java虚拟机不和包括Java在内的任何语言绑定,它只与字节码文件这种特定的二进制文件格式所关联. Class文件结构不仅仅是JVM的执行入口,更是Java生态圈的基础和核心. 字节码文件内容是什么 字节码是一种二进制的类文件,他的内容是JVM指令,而…

OpenAI竞对再被谷歌加注!4.5亿美元新融资到位,累计已吸金14.5亿美元

量子位 | 公众号 QbitAI OpenAI之外&#xff0c;第二不差钱的AI初创公司出现了&#xff01; 研发出ChatGPT最强竞品Claude的Anthropic公司&#xff0c;在谷歌投资之后&#xff0c;再次官宣获得了4.5亿美元C轮融资。 这轮收购之后&#xff0c;Anthropic资金一跃达到14.5亿美元…

CPLEX Studio OPL项目介绍

参考B站视频&#xff1a;cplex入门到精通 1.理解 OPL 项目 CPLEX Studio 处理 OPL 项目文件(.project)、数据文件(.dat)、模型文件 (.mod)、设置文件(.ops)和运行配置(.oplproject)。 文件类型扩展名作用份数说明模型文件.mod模型存储和数据1~n必须数据文件.dat数据存储0~n非…

【代码随想录】刷题Day42

1.01背包问题 问题介绍&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 1.二维数组实现思想 1.dp[i][j]的含义&#xff1a;首先…

头羊部落亮相首届校园预制菜展,成为预制菜行业领头羊

由北京工商大学与北京市学校基建后勤管理事务中心共同主办的首届预制菜产业与智慧团餐高质量发展研讨会暨校园食材展&#xff08;以下简称大会&#xff09;于2023年5月26-27日在北京工商大学举办。 △首届预制菜产业与智慧团餐高质量发展研讨会在北京工商大学隆重举行 △预制菜…

【Python map()、filter() 和 reduce()】零基础也能轻松掌握的学习路线与参考资料

Python编程中常使用map()、filter()和reduce()函数来实现对数据集的操作&#xff0c;尤其是在处理数据时&#xff0c;这些函数非常有用。在本文中&#xff0c;将介绍这些函数的学习路线和优秀实践&#xff0c;并提供一些参考资料供读者参考。 一、Python map() 函数 Python中…

附录5-黑马头条案例

目录 1 效果 2 组件库vant 2.1 安装 2.2 配置 2.3 项目中的使用 2.3.1 引用 2.3.2 tabbar 底部切换 2.3.3 navbar 顶部标题 2.3.4 van-list 上拉触底更新 2.3.5 van-pull-refresh 下拉更新 2.3.6 v-cell 2.3.7 van-icon 2.3.8 自定义风格 3 保持滚…

做接口测试时遇到接口加密了该如何处理

对明文编码生成信息摘要&#xff0c;以防止被篡改。比如MD5使用的是Hash算法&#xff0c;无论多长的输入&#xff0c;MD5都会输出长度为128bits的一个串。 摘要算法不要秘钥&#xff0c;客户端和服务端采用相同的摘要算法即可针对同一段明文获取一致的密文。 对称加密 对称加…

C语言获取AIX单网卡的多IP地址

环境配置 在AIX上&#xff0c;可以使用smitty tcpip命令给单个网卡配置多个IP别名。操作步骤如下&#xff1a; 选择Further Configuration 选择Network Interfaces 选择 Network Interfaces Selection 选择 Configure Aliases 5.选择Add an IPV4 Network Alias 选择需要配…

Vue3:组合式写法入门

Vue3&#xff1a;组合式写法入门 Date: May 11, 2023 认识Vue3 1. Vue3组合式API体验 通过 Counter 案例 体验Vue3新引入的组合式API <script> export default {data(){return {count:0}},methods:{addCount(){this.count}} } </script><script setup> imp…

超声波都应用在哪些领域中?功率放大器如何放大超声波?

超声波是声波的一部分&#xff0c;它的频率高于20kHz&#xff0c;是无法被人耳听到的声波&#xff0c;超声波与声波有共通之处&#xff0c;即它们都是由物体振动所产生&#xff0c;只能在介质中进行传播。无论是在自然界&#xff0c;还是人们的日常生活之中&#xff0c;超声波都…

Power BI DAX函数

1、聚合函数——由表达式定义的列或表中所有行的&#xff08;标量&#xff09;值&#xff0c;例如计数、求和、平均值、最小值或最大值。 函数说明APPROXIMATEDISTINCTCOUNT在列中返回唯一值的估计计数AVERAGE返回列中所有数字的平均值&#xff08;算术平均值&#xff09;AVER…

基于 Python 和深度学习技术实现的人体姿态识别

人体姿态识别是计算机视觉领域的一个重要应用&#xff0c;它通过识别人体的关键点和关节位置&#xff0c;能够准确地判断人体的姿态和动作。这项技术可以应用在很多领域&#xff0c;比如运动训练、医疗康复、安保监控等&#xff0c;为人们的生活和工作带来了很大的便利和效益。…

Fiddler抓包工具之fiddler设置弱网测试

弱网测试 概念&#xff1a;弱网看字面意思就是网络比较弱&#xff0c;我们通称为信号差&#xff0c;网速慢。 意义&#xff1a;模拟在地铁、隧道、电梯和车库等场景下使用APP &#xff0c;网络会出现延时、中断和超时等情况。 Fiddler弱网测试流程&#xff1a; 一、限速操作…