为何Drools规则引擎仅执行一次空条件规则?
我搭建了一个基础的Drools规则引擎,仅配置了一条规则:
rule "Hello World" when then System.out.println("Hello World!"); end
我在Java线程的循环中运行该应用,每次循环都会调用有状态Kie Session的fireAllRules()方法触发规则。第一次循环成功打印了"Hello World!",但后续循环中该规则不再触发。
相关代码
run方法:
@Override public void run() { // Fire the rules System.out.println("Firing rules"); kSession.fireAllRules(); }
Kie Session初始化代码:
KieServices ks = KieServices.Factory.get(); KieContainer kContainer = ks.getKieClasspathContainer(); KieBase kBase1 = kContainer.getKieBase("KBase1"); kSession = kBase1.newKieSession();
环境信息
- Maven依赖:
- drools-engine(版本9.44.0-Final)
- drools-xml-support(版本9.44.0-Final)
- drools-mvel(版本9.44.0-Final)
- 使用插件:
- kie-maven-plugin(版本9.44.0-Final)
我猜测这和引擎的推理机制有关,但对其原理理解不足,恳请解答!
核心原因
Drools的**有状态Session(Stateful Kie Session)**会维护规则的激活状态(Agenda)和工作内存(Working Memory)。对于没有when条件的规则(即永远满足触发条件的规则),首次调用fireAllRules()时,规则会被执行,Drools会标记该规则已被激活过——默认情况下不会重复触发,这是为了避免规则无限循环执行的设计。
解决方案
根据场景需求,可选择以下三种方式解决:
1. 使用无状态Session(Stateless Kie Session)
如果不需要维护工作内存状态,每次触发规则都要从头执行,改用无状态Session即可:
// 初始化无状态Session StatelessKieSession kSession = kBase1.newStatelessKieSession(); // 触发规则 @Override public void run() { System.out.println("Firing rules"); kSession.execute(new Object()); // 无状态Session需传入任意对象(即使未使用) }
无状态Session每次执行都会重新初始化工作内存和Agenda,因此每次调用都会触发规则。
2. 重置Session的激活状态
若必须使用有状态Session,可在每次fireAllRules()后重置Agenda,清除已激活的规则记录:
@Override public void run() { System.out.println("Firing rules"); kSession.fireAllRules(); // 重置Agenda,让规则重新变为可激活状态 kSession.getAgenda().clear(); }
下次调用fireAllRules()时,规则会被重新评估并触发。
3. 给规则添加可变化的触发条件
如果希望规则能根据状态变化重复触发,可给规则添加when条件,比如引入计数对象控制触发逻辑:
首先定义计数器类:
public class Counter { private int count; // 省略getter、setter方法 }
修改规则:
rule "Hello World" when $counter : Counter() // 匹配工作内存中的Counter对象 then System.out.println("Hello World!"); // 更新计数器状态,确保规则可重复匹配 modify($counter) { setCount($counter.getCount() + 1) }; end
初始化Session时将Counter对象插入工作内存:
// Session初始化完成后执行 Counter counter = new Counter(); kSession.insert(counter);
这种方式下,每次fireAllRules()都会检查when条件是否满足,只要工作内存中存在对应对象(或状态更新),规则就会触发。
内容的提问来源于stack exchange,提问作者tarcin

