当前位置: 首页 > news >正文

Drools 议程组(AgendaGroup)执行顺序实验

🚀 Drools 议程组(AgendaGroup)执行顺序实验

📌 前言

在使用 Drools 规则引擎时,AgendaGroup(议程组)是一个重要的机制,它允许我们控制规则的执行顺序。默认的议程组 MAIN 包含所有没有指定议程组的规则,除非其他议程组有焦点,否则这个默认议程组会第一个执行。但当我们使用 setFocus() 方法来设置议程组的焦点时,会影响规则的执行顺序。每次setFocus方法被调用,drools会在堆栈头添加指定的议程组。ksession.getAgenda().getAgendaGroup( "Group A" ).clear(); 也可以通过clear()方法取消议程组的的执行。

本篇博客通过实验来验证 setFocus() 的执行逻辑,并探讨如何正确控制规则的执行顺序。


📝 实验目标

  1. 验证 setFocus() 采用后进先出(LIFO,Last In First Out)执行机制
  2. 测试多个 AgendaGroup 规则的执行顺序
  3. 探讨如何调整 AgendaGroup 的执行顺序

📌 1. 规则定义

我们定义两个规则,分别属于 report 议程组 和 calculation 议程组,每个规则触发时都会打印日志并记录执行顺序。

kmodule.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://www.drools.org/xsd/kmodule">
         
    <kbase name="test_focus_sessionKB" packages="rules">
        <ksession name="test_focus_session"/>
    </kbase>

</kmodule>

Kmodule.xmlpackages包名和下面test_setFoucus.drl的相对应

test_setFoucus.drl 规则文件

package rules

global java.util.List logList;  // 用于记录规则执行顺序

rule "Report Rule"
    agenda-group "report"  // 规则属于 report 组
when
    $msg : String(this == "trigger")
then
    logList.add("Report executed");
    System.out.println("【Report】Rule executed");
end

rule "Calculation Rule"
    agenda-group "calculation"  // 规则属于 calculation 组
when
    $msg : String(this == "trigger")
then
    logList.add("Calculation executed");
    System.out.println("【Calculation】Rule executed");
end

rule "ttest"
    agenda-group "ttest"  // 规则属于 ttest 组
when
    $msg : String(this == "trigger")
then
    logList.add("ttest");
    System.out.println("ttest");
end

📌 2. Java 代码

在 Java 代码中,我们:

  • 创建 KieSession 并设置全局变量 logList,用于记录执行顺序。
  • 使用 setFocus() 设定议程组的执行顺序。
  • 执行 fireAllRules(),触发规则执行。

TestSetFocus.java 规则文件

package com.neo.drools;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.Agenda;
import java.util.ArrayList;
import java.util.List;

public class TestSetFocus {
    public static void main(String[] args) {
        // 获取 KieServices 工厂实例
        KieServices ks = KieServices.Factory.get();

        // 获取 KieContainer(Drools 规则引擎容器),用于管理 KieSession
        KieContainer kc = ks.getKieClasspathContainer();

        // 执行 Drools 规则
        execute(kc);
    }

    public static void execute(KieContainer kc) {
        // 创建 KieSession(Drools 规则引擎的会话),用于执行规则
        KieSession ksession = kc.newKieSession("test_focus_session");

        // 防止 KieSession 为空,避免 NullPointerException
        if (ksession == null) {
            throw new RuntimeException("KieSession 创建失败,请检查 kmodule.xml 和 rules.drl 规则文件!");
        }

        // 创建 List 作为全局变量,用于记录规则执行顺序
        List<String> logList = new ArrayList<>();
        ksession.setGlobal("logList", logList); // 将 logList 设置为 Drools 规则中的全局变量

        // 插入触发事实(用于匹配规则)
        ksession.insert("trigger");

        // 获取 Agenda(议程)对象,用于管理规则执行顺序
        Agenda agenda = ksession.getAgenda();

        // 设置 report 组的规则执行(先压入 report 组,但后执行)
        System.out.println("\n===== Setting Focus: report =====");
        agenda.getAgendaGroup("report").setFocus();

        // 设置 calculation 组的规则执行(再压入 calculation 组,但先执行)
        System.out.println("\n===== Setting Focus: calculation =====");
        agenda.getAgendaGroup("calculation").setFocus();

        // 触发规则执行
        System.out.println("\n===== Firing All Rules =====");
        ksession.fireAllRules();

        // 打印规则执行顺序
        System.out.println("\n===== Execution Order =====");
        System.out.println(logList);

        // 释放 KieSession 资源
        ksession.dispose();
    }
}

📌 3. 实验结果

执行 Java 代码,得到如下输出:

===== Setting Focus: report =====

===== Setting Focus: calculation =====

===== Firing All Rules =====CalculationRule executed
【ReportRule executed

===== Execution Order =====
[Calculation executed, Report executed]

进程已结束,退出代码为 0

🔹 结果分析

  • setFocus("report") 先调用,setFocus("calculation") 后调用。
  • Drools 采用 LIFO(后进先出),所以 calculation 先执行,然后 report 后执行。
  • 可以看到rule "ttest"压根就不会被加入判断,因为没给它用setFocus,它并不是焦点规则组。

默认的议程组 MAIN 包含所有没有指定议程组的规则,除非其他议程组有焦点,否则这个默认议程组会第一个执行。但当我们使用 setFocus() 方法来设置议程组的焦点时,会影响规则的执行顺序。每次setFocus方法被调用,drools会在堆栈头添加指定的议程组。ksession.getAgenda().getAgendaGroup( "Group A" ).clear(); 也可以通过clear()方法取消议程组的的执行。

相关文章:

  • WordPress Elementor提示错误无法保存500的解决指南
  • DeepSeek R1/V3满血版——在线体验与API调用
  • 美国移民局公告:放弃试用入籍考试新版本试题,继续沿用旧版!
  • 【编程技巧】使用hash保存异位字符串
  • 教师教学技能大赛流程方案及细则
  • C#最新语言特性
  • Deepseek R1 和其他的大模型 共同辅助决策交通出行方案
  • 英语场景(一)
  • 当我尝试用AI组团去编故事
  • UDP、TCP的区别
  • 1.4 嵌入式系统的软件
  • 提升 AI 服务的稳定性:Higress AI 网关的降级功能介绍
  • 区块链共识机制详解
  • CentOS的ssh复制文件
  • C++ DAY3
  • SMT贴片车间高效运作实战指南
  • uniapp 网络请求封装(uni.request 与 uView-Plus)
  • 《深度学习实战》第2集:卷积神经网络(CNN)与图像分类
  • BDF7与glm的对话
  • 学习笔记-沁恒第四讲-米醋
  • “子宫内膜异位症”相关论文男性患者样本超六成?福建省人民医院展开调查
  • 中国公民免签赴马来西亚的停留天数如何计算?使馆明确
  • 上海成五一国内最热门的入境游目的地,国际消费明显提升
  • 美国得克萨斯州发生5.4级地震,震源深度10千米
  • 美妙的下午
  • 9米长林肯车开进安徽“皖南川藏线”致拥堵数小时,车主回应争议称配合调查