JDK21 与 Drools 9.44.0.Final 规则引擎

JDK21 与 Drools 9.44.0.Final 规则引擎

  • 一.规则引擎基本理解
  • 二.Drools 基本概念
    • 1.kmodule默认配置文件定义
    • 2.规则文件
    • 3.引擎简介
    • 4.概念说明
  • 三.Drools 示例
    • 1.Attribute 关键字和说明
      • 1.优先级
      • 2.是否可用
      • 3.生效时间控制
      • 4.NO-LOOP 死循环控制
      • 5.分组测试
      • 6.Duration 休眠测试
      • 7.定时器测试

一.规则引擎基本理解

前言:规则引擎的用途,可以通过修改规则配置,从而动态调整业务规则,搭配可视化工具,适合于业务人员随时调整规则。相对于 HardCode , 虽然需要一定学习成本,但具备以下优势

  • 简化系统架构,提高可维护性
  • 规则轻量、多样化
  • 任意修改、任意加载,动态处理
  • 脚本支持、复杂逻辑支持、可扩展与复用
  • 上下文隔离,有状态与无状态会话

适用场景

  • 动作监听
  • 打折促销
  • 数据过滤
  • 消息路由
  • 会员管理
  • 积分管理

二.Drools 基本概念

Drools 是 JBoss 旗下 KIE (Knowledge is everything)体系的一个子产品,基于 Java 语言开发,用于进行规则解析与执行。

1.kmodule默认配置文件定义

默认配置文件:src/main/resources/META-INF/kmodule.xml

kbase 标签

属性 含义
name kbase 名称,全局唯一,不允许重复,可以理解为工作空间或命名空间
includes 包含,用于将多个kbase封装到一起,通过【,】分割
packages 包名,即规则文件的位置,通过【,】分割可配置多个
default 是否为默认命名空间
equalsBehavior 相等的判断逻辑,用代码说明就是 == 和 equals 的区别,即 identity 和 equality
eventProcessingMode 事件模式,stream 模式允许进行时间推理,cloud为普通fact
declarativeAgenda disable或enable 用于控制规则间逻辑关系

ksession 标签

属性 含义
name ksession 名称,全局唯一,不允许重复
type stateful 有状态,对 working memory 内数据多次处理 stateless 无状态
default 是否为默认会话
clockType 时钟类型,realtime 系统时钟 pseudo 伪时钟,可用于单元测试
beliefSystem 信仰系统,用于控制资源访问和冲突

2.规则文件

规则配置文件位置:rc/main/resources/*.drl

规则文件定义

关键字 含义
package 包名,同一个包下的查询或者函数可直接调用
import 导入类或静态方法
global 定义全局变量
function 自定义函数
query 查询
rule - end 规则体

规则体定义

关键字 含义
rule 规则体定义开始关键字
attribute 规则属性
when 关键字,后面跟规则条件,空视为 true
then 关键字,后面跟规则处理,空则不处理
end 规则体定义结束关键字

规则体条件定义

符号 含义
< 小于
<= 小于等于
== 等于
>= 大于等于
> 大于
!= 不等于
contains 包含
not contains 不包含
memberOf 属于
not memberOf 不属于
matches 正则匹配
not matches 正则不匹配

3.引擎简介

Drools 规则引擎构成

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

其中推理引擎又包括:

  • Pattern Matcher(匹配器)
  • Agenda(议程)
  • Execution Engine(执行引擎)

4.概念说明

概念 含义
KieServices KIE的顶层抽象,用于创建、管理和获取KieContainer、KieSession等
KieContainer kbase 实例化后的一个容器,一组规则实例
KieSession 用于与 kbase 实例交互的一个会话
kieModules 通过 xml 配置进行 kbase、ksession 的声明
KieRepository 用于存放 KieModule 的单例对象,即仓库
KieProject 初始化 KieModule,并将其存放到KieRepository仓库中,然后 KieContainer 可以通过 KieProject 来查找 KieModule ,并根据这些信息构造KieBase 和 KieSession
ClasspathKieProject KieProject的一个具体实现,从根目录加载kmodule.xml配置,从而初始化一个 kiemodule
Working Memory 工作内存,将待处理数据插入进去,drools 进行处理
Fact 一个普通的 JavaBean 插入到 Working Memory 后,drools 称之为Fact 对象
Rule Base 规则库
Pattern Matcher 将规则库规则与工作内存中事实对象进行匹配,成功则将规则放到议程
Agenda 议程,存放上一步通过匹配器进行模式匹配后被激活的规则
Execution Engine 执行议程内激活的规则

三.Drools 示例

Drools 官方文档

不同版本差异较大,本示例对应版本如下

环境 版本
JDK jdk-21.0.1
Drools 9.44.0.Final

工程结构

JDK21 与 Drools 9.44.0.Final 规则引擎_第1张图片

Pom 依赖


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>drools-demoartifactId>
    <version>1.0-SNAPSHOTversion>

    <properties>
        <maven.compiler.source>21maven.compiler.source>
        <maven.compiler.target>21maven.compiler.target>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <drools.version>9.44.0.Finaldrools.version>
    properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.droolsgroupId>
                <artifactId>drools-bomartifactId>
                <type>pomtype>
                <scope>importscope>
                <version>${drools.version}version>
            dependency>
        dependencies>
    dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.droolsgroupId>
            <artifactId>drools-engineartifactId>
        dependency>
        <dependency>
            <groupId>org.droolsgroupId>
            <artifactId>drools-mvelartifactId>
        dependency>
        <dependency>
            <groupId>org.droolsgroupId>
            <artifactId>drools-model-compilerartifactId>
        dependency>
        <dependency>
            <groupId>org.droolsgroupId>
            <artifactId>drools-xml-supportartifactId>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13.2version>
        dependency>

    dependencies>

project>

kmodule.xml 配置,默认在如下目录 src\main\resources\META-INF


<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule">

    
    <kbase name="my_kbase" packages="rules.*" default="true">
        
        <ksession name="my_ks" clockType="realtime" default="true"/>
    kbase>
kmodule>

1.Attribute 关键字和说明

关键字 含义 示例
salience 整型,规则优先级 salience 10
enabled 布尔值,规则是否可用 enabled true
date-effective 字符串,规则在某个日期或时间后可用 date-effective “4-Sep-2018”
date-expires 字符串,规则在某个日期或时间后不可用 date-expires “4-Oct-2018”
no-loop 布尔值,表示当前规则是否允许被循环激活 no-loop true
activation-group 用于控制所属 internalMatch 分组,组内只有一个规则能激活 activation-group “GroupName”
duration 长整型,经过多少毫秒后规则满足条件时仍可用,类似于休眠指定时间 duration 10000
timer 定时配置 timer ( int: 30s 5m ) 延迟30秒后每5分钟
timer ( cron:* 0/15 * * * ? ) Cron 表达式
calendar 定时配置 calendars “* * 0-7,18-23 ? * *” Quartz 表达式
auto-focus 布尔值,当前规则执行时自动提交给所属议程组 auto-focus true
lock-on-active 布尔值,避免规则流组或议程组立即读取规则的更新 lock-on-active true
dialect 代码表达式方言,JAVA 或 MVEL dialect “JAVA”

1.优先级

新建 drl 文件

package rules.salience

rule "salience-1"
    salience 1
    when
    then
        System.out.println(1);
end
package rules.salience

rule "salience-2"
    salience 2
    when
    then
        System.out.println(2);
end

package rules.salience

rule "salience-3"
    salience 3
    when
    then
        System.out.println(3);
end

测试代码:

package org.example;


import org.kie.api.KieServices;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.rule.AgendaFilter;

/**
 * @author Administrator
 */
public class DroolsApp {
    public static void main(String[] args) {

        //KIE 服务
        KieServices services = KieServices.Factory.get();
        //KIE 容器
        KieContainer container = services.getKieClasspathContainer();
        //会话配置
        KieSessionConfiguration ksc = KieServices.Factory.get().newKieSessionConfiguration();
        ksc.setOption( TimedRuleExecutionOption.YES );

        String ksName = "my_ks";

        //获取新会话
        KieSession session = container.newKieSession(ksName,ksc);
        //激活所有规则
        session.fireAllRules();
        //最多激活两个
//        session.fireAllRules(2);

        //过滤规则
//        AgendaFilter filter = match -> {
//            Rule rule = match.getRule();
//            if (rule.getName().equals("salience-2")){
//                return true;
//            }
//            return false;
//        };
//        session.fireAllRules(filter);

        //销毁
        //session.destroy();
    }
}

结果

JDK21 与 Drools 9.44.0.Final 规则引擎_第2张图片

2.是否可用

将上面的 salience_2.drl 修改为

package rules.salience

rule "salience-2"
    enabled false
    salience 2
    when
    then
        System.out.println(2);
end

重新执行结果,规则 2 已不可用

JDK21 与 Drools 9.44.0.Final 规则引擎_第3张图片

3.生效时间控制

将 salience_1.drl 修改为如下,注意时间格式 [ d-MMM-yyyy ]

package rules.salience

rule "salience-1"
    date-effective "17-dec-2023"
    salience 1
    when
    then
        System.out.println(1);
end

将 salience_3.drl 修改为如下,注意时间格式 [ d-MMM-yyyy ]

package rules.salience

rule "salience-3"
    date-expires "17-dec-2023"
    salience 3
    when
    then
        System.out.println(3);
end

执行结果 salience_1.drl 开始生效 salience_3.drl 开始失效

JDK21 与 Drools 9.44.0.Final 规则引擎_第4张图片

4.NO-LOOP 死循环控制

定义一个测试用的对象

package org.entity;

/**
 * @author zhuwd && moon
 * @Description
 * @create 2023-12-17 15:39
 */

public class NoLoopEntity {

    private Integer num;

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer age) {
        this.num = age;
    }
}

新建目录 rules\no_loop ,并定义规则文件

package rules.no_loop
import org.entity.NoLoopEntity

rule "no-loop-1"
    no-loop false

    when
        //判断并取值
        $person : NoLoopEntity(num > 0 , $tmp : (num - 1))
    then
        //设置 num
        $person.setNum($tmp);
        //更新
        update($person);
        System.out.println($tmp);
end

测试代码

package org.example;


import org.entity.NoLoopEntity;
import org.kie.api.KieServices;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.rule.AgendaFilter;

/**
 * @author Administrator
 */
public class DroolsApp {
    public static void main(String[] args) {

        //KIE 服务
        KieServices services = KieServices.Factory.get();
        //KIE 容器
        KieContainer container = services.getKieClasspathContainer();
        //会话配置
        KieSessionConfiguration ksc = KieServices.Factory.get().newKieSessionConfiguration();
        ksc.setOption( TimedRuleExecutionOption.YES );

        String ksName = "my_ks";

        //获取新会话
        KieSession session = container.newKieSession(ksName,ksc);
        //过滤规则
        AgendaFilter filter = match -> {
            Rule rule = match.getRule();
            if (rule.getName().equals("no-loop-1")){
                return true;
            }
            return false;
        };

        NoLoopEntity noLoop = new NoLoopEntity();
        noLoop.setNum(10);

        session.insert(noLoop);
        session.fireAllRules(filter);

        //销毁
        //session.destroy();
        
    }
}

no-loop false 允许循环结果如下

JDK21 与 Drools 9.44.0.Final 规则引擎_第5张图片

no-loop true 不允许循环结果如下

在这里插入代码片

JDK21 与 Drools 9.44.0.Final 规则引擎_第6张图片

5.分组测试

新建包 rules\group 并定义规则

package rules.group

rule "group-1"
    activation-group "my-group-1"
    when
    then
        System.out.println("Group:"+1);
end

rule "group-2"
    activation-group "my-group-2"
    when
    then
        System.out.println("Group:"+2);
end

rule "group-3"
    activation-group "my-group-3"
    when
    then
        System.out.println("Group:"+3);
end

测试类


package org.example;


import org.kie.api.KieServices;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.rule.AgendaFilter;

/**
 * @author Administrator
 */
public class DroolsApp {
    public static void main(String[] args) {

        //KIE 服务
        KieServices services = KieServices.Factory.get();
        //KIE 容器
        KieContainer container = services.getKieClasspathContainer();
        //会话配置
        KieSessionConfiguration ksc = KieServices.Factory.get().newKieSessionConfiguration();
        ksc.setOption( TimedRuleExecutionOption.YES );

        String ksName = "my_ks";

        //获取新会话
        KieSession session = container.newKieSession(ksName,ksc);
        //过滤规则
        AgendaFilter filter = match -> {
            Rule rule = match.getRule();
            if (rule.getName().startsWith("group-")){
                return true;
            }
            return false;
        };

        session.fireAllRules(filter);

        //销毁
        //session.destroy();

    }
}

测试结果

JDK21 与 Drools 9.44.0.Final 规则引擎_第7张图片

将上面三个规则体的 activation-group 统一修改为 my-group

JDK21 与 Drools 9.44.0.Final 规则引擎_第8张图片

6.Duration 休眠测试

新建包 rules\duration 并定义规则

package rules.duration
global java.lang.Integer num

rule "my-duration"
    duration 1000
    when
        Integer( $iv: intValue > num )
    then
        System.out.println("duration:" + $iv);
        System.out.println("duration:" + System.currentTimeMillis());
end

测试类

package org.example;

import org.kie.api.KieServices;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.rule.AgendaFilter;

/**
 * @author Administrator
 */
public class DroolsApp {
    public static void main(String[] args) throws InterruptedException {

        //KIE 服务
        KieServices services = KieServices.Factory.get();
        //KIE 容器
        KieContainer container = services.getKieClasspathContainer();
        //会话配置
        KieSessionConfiguration ksc = KieServices.Factory.get().newKieSessionConfiguration();
        ksc.setOption( TimedRuleExecutionOption.YES );

        String ksName = "my_ks";

        //获取新会话
        KieSession session = container.newKieSession(ksName,ksc);

        //定义全局变量
        session.setGlobal("num",0);
        session.insert(1);
        //过滤规则
        AgendaFilter filter = match -> {
            Rule rule = match.getRule();
            if (rule.getName().startsWith("my-duration")){
                return true;
            }
            return false;
        };

        System.out.println("class:" + System.currentTimeMillis());
        //激活
        session.fireAllRules(filter);

        //销毁
        //session.destroy();

    }
}

执行结果

JDK21 与 Drools 9.44.0.Final 规则引擎_第9张图片

7.定时器测试

新建包 rules\time 并定义规则

package rules.time

rule "timer-1"
    enabled false
    timer ( cron:0/10 * * * * ? )
    when
    then
        System.out.println("timer-1:" + System.currentTimeMillis());
end

rule "timer-2"
    enabled false
    timer ( int: 10s 3s )
    when
    then
        System.out.println("timer-2:" + System.currentTimeMillis());
end

测试类

package org.example;

import org.kie.api.KieServices;
import org.kie.api.definition.rule.Rule;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.TimedRuleExecutionOption;
import org.kie.api.runtime.rule.AgendaFilter;

/**
 * @author Administrator
 */
public class DroolsApp {
    public static void main(String[] args) throws InterruptedException {

        //KIE 服务
        KieServices services = KieServices.Factory.get();
        //KIE 容器
        KieContainer container = services.getKieClasspathContainer();
        //会话配置
        KieSessionConfiguration ksc = KieServices.Factory.get().newKieSessionConfiguration();
        ksc.setOption( TimedRuleExecutionOption.YES );

        String ksName = "my_ks";

        //获取新会话
        KieSession session = container.newKieSession(ksName,ksc);

        //过滤规则
        AgendaFilter filter = match -> {
            Rule rule = match.getRule();
            if (rule.getName().startsWith("timer")){
                return true;
            }
            return false;
        };

        System.out.println("class  :" + System.currentTimeMillis());

        //激活
        session.fireAllRules(filter);

        //销毁
        //session.destroy();

    }
}

timer-1 测试结果 每 10 秒

JDK21 与 Drools 9.44.0.Final 规则引擎_第10张图片

timer-2 测试结果 延迟 10 秒后每 3 秒

JDK21 与 Drools 9.44.0.Final 规则引擎_第11张图片

你可能感兴趣的:(JavaWeb,服务框架,drools,jdk,template,模板引擎,解释器)