Drools 7.2:不使用KieScanner,如何手动刷新KieContainer?
刚好之前做过类似的Drools动态规则更新的场景,针对你用MongoDB存DRL字符串、不用KieScanner手动刷新KieContainer的需求,给你梳理一套可行的实现方案:
手动刷新KieContainer的实现步骤(Drools 7.2)
核心思路
既然规则是以字符串形式存在MongoDB,我们完全可以绕过KieScanner,通过Drools的核心API手动从DRL字符串重新构建KieModule,再生成新的KieContainer来替换旧实例——这是最直接可靠的动态更新方式。
具体实现代码
1. 封装DRL字符串转KieContainer的工具方法
这个方法负责把从MongoDB拉取到的DRL字符串编译成可用的KieContainer:
import org.kie.api.KieServices; import org.kie.api.builder.KieBuilder; import org.kie.api.builder.KieFileSystem; import org.kie.api.builder.KieModule; import org.kie.api.builder.Message; import org.kie.api.runtime.KieContainer; import java.util.List; public KieContainer buildKieContainerFromDrls(List<String> drlStrings) { KieServices kieServices = KieServices.Factory.get(); KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); // 给每个DRL字符串分配唯一的虚拟路径,模拟文件系统中的规则文件 int ruleIndex = 0; for (String drlContent : drlStrings) { String virtualFilePath = "src/main/resources/drl/dynamic-rule-" + ruleIndex + ".drl"; kieFileSystem.write(virtualFilePath, drlContent); ruleIndex++; } // 编译规则,注意处理编译错误 KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem); kieBuilder.buildAll(); if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) { throw new RuntimeException("规则编译失败:" + kieBuilder.getResults().getMessages()); } // 生成并返回新的KieContainer KieModule kieModule = kieBuilder.getKieModule(); return kieServices.newKieContainer(kieModule.getReleaseId()); }
2. 在定时任务中替换旧的KieContainer
结合你已经实现的MongoDB定时拉取逻辑,只需要在拉取到最新规则后执行替换:
// 假设你有一个全局的KieContainer实例,用volatile保证线程可见性 private volatile KieContainer currentKieContainer; // 定时任务执行逻辑 public void refreshRulesFromMongo() { // 1. 从MongoDB拉取最新的DRL规则字符串列表 List<String> latestDrls = yourMongoDao.getAllRuleContents(); // 2. 构建新的KieContainer KieContainer newKieContainer = buildKieContainerFromDrls(latestDrls); // 3. 替换全局实例(线程安全) KieContainer oldContainer = currentKieContainer; currentKieContainer = newKieContainer; // 4. 清理旧资源,避免内存泄漏 if (oldContainer != null) { oldContainer.dispose(); } // 5. 如果有正在使用的KieSession,需要关闭旧Session并从新容器创建 // oldKieSession.dispose(); // KieSession newSession = currentKieContainer.newKieSession(); }
关键注意事项
- 线程安全:全局的
KieContainer一定要用volatile修饰或者放在AtomicReference中,避免多线程环境下的可见性问题。 - 编译错误处理:必须检查
KieBuilder的编译结果,否则错误规则会导致后续规则执行异常。 - 资源清理:替换旧容器后一定要调用
dispose()释放资源,防止内存泄漏。 - 版本追踪(可选):如果需要区分规则版本,可以自定义
ReleaseId,比如用时间戳作为版本号:ReleaseId releaseId = kieServices.newReleaseId("com.yourcompany", "dynamic-rules", String.valueOf(System.currentTimeMillis())); kieFileSystem.generateAndWritePomXML(releaseId);
内容的提问来源于stack exchange,提问作者anonymous
相关产品推荐
相关产品推荐

