Drools Agenda Group未按预期工作,规则执行顺序异常
核心原因
你在命令序列中最后设置的议程组焦点是「final」,Drools的议程组焦点是覆盖式的,后设置的焦点会直接覆盖之前的设置。当执行插入对象命令时,当前活跃的议程组是「final」,引擎会优先处理该组中满足条件的规则,这就导致「final」组的rule2先执行,不符合预期。
虽然「initial」组的规则设置了auto-focus true,但该属性的作用是当规则条件满足时,自动将其所在的议程组设为焦点——但如果此时当前焦点组(「final」)的规则已经激活并进入执行队列,引擎会先完成当前焦点组的规则执行,之后才会响应auto-focus的焦点切换,无法保证「initial」组优先执行。
另外注意你代码中的拼写错误:BatchExecutoinCommandImpl应为BatchExecutionCommandImpl,executionCommand应为你定义的commands变量,这些错误可能导致命令逻辑异常。
解决方案
1. 调整焦点命令顺序(推荐)
将「initial」的焦点命令放在最后,确保插入对象时,当前焦点是「initial」。修改后的代码如下:
val trigger(kieContainer: KieContainer) = { val kieSession = kieContainer.newStatelessKieSession val commands = new BatchExecutionCommandImpl() // 先设置final组焦点(可选,若不需要可移除) val agendaGroup1 = new AgendaGroupSetFocusCommand("final") val agendaGroup = new AgendaGroupSetFocusCommand("initial") commands.addCommand(agendaGroup1) commands.addCommand(agendaGroup) commands.addCommand(CommandFactory.newInsert(customObject, "obj")) kieSession.execute(commands) }
此时插入对象时,当前焦点是「initial」,引擎会优先执行该组规则,之后auto-focus或手动设置的焦点会切换到「final」组执行后续规则。
2. 分阶段执行规则
如果需要严格隔离两组规则的执行顺序,可以分两次执行命令(无状态会话每次execute是独立执行周期):
val trigger(kieContainer: KieContainer) = { val kieSession = kieContainer.newStatelessKieSession // 第一阶段:执行initial组规则 val initialCommands = new BatchExecutionCommandImpl() initialCommands.addCommand(new AgendaGroupSetFocusCommand("initial")) initialCommands.addCommand(CommandFactory.newInsert(customObject, "obj")) kieSession.execute(initialCommands) // 第二阶段:执行final组规则 val finalCommands = new BatchExecutionCommandImpl() finalCommands.addCommand(new AgendaGroupSetFocusCommand("final")) finalCommands.addCommand(CommandFactory.newInsert(customObject, "obj")) kieSession.execute(finalCommands) }
3. 正确使用auto-focus
如果希望auto-focus生效抢焦点,需确保插入对象时,没有手动设置其他组的焦点(即只保留「initial」的焦点命令,或不设置任何焦点)。此时当「initial」组规则条件满足时,auto-focus会自动将焦点切换到该组,优先执行其规则。
内容的提问来源于stack exchange,提问作者Shashank Agrawal

