Drools 议程组(AgendaGroup)执行顺序实验
🚀 Drools 议程组(AgendaGroup)执行顺序实验
📌 前言
在使用 Drools 规则引擎时,AgendaGroup
(议程组)是一个重要的机制,它允许我们控制规则的执行顺序。默认的议程组 MAIN 包含所有没有指定议程组的规则,除非其他议程组有焦点,否则这个默认议程组会第一个执行。但当我们使用 setFocus()
方法来设置议程组的焦点时,会影响规则的执行顺序。每次setFocus
方法被调用,drools会在堆栈头添加指定的议程组。ksession.getAgenda().getAgendaGroup( "Group A" ).clear();
也可以通过clear()方法取消议程组的的执行。
本篇博客通过实验来验证 setFocus()
的执行逻辑,并探讨如何正确控制规则的执行顺序。
📝 实验目标
- 验证
setFocus()
采用后进先出(LIFO,Last In First Out)执行机制。 - 测试多个
AgendaGroup
规则的执行顺序。 - 探讨如何调整
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.xml
的packages
包名和下面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 =====
【Calculation】Rule executed
【Report】Rule 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()方法取消议程组的的执行。