You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 09:58:48