Drools规则引擎

103 阅读2分钟

规则引擎代码: List rules = RuleService.selectList(new RuleQueryParam("TAG")); if (CollectionUtils.isEmpty(rules)) { log.error("获取规则异常"); return null; }

    KieHelper helper = new KieHelper();
    templateRules.forEach(droolsRule -> helper.addContent(droolsRule.getContent(), ResourceType.DRL));
    KieSession ksession = helper.build().newKieSession();
    ksession.insert(param);
    ksession.fireAllRules();
    ksession.dispose();

    return covert(param.getResults());

规则:


import com.platform.**.param.LabelParam;
import com.platform.**.vo.LabelResultVO;

rule "Enterprise Label"
    when
        $info : LabelParam(enterpriseLabel != null)
        $tag : String() from $info.getEnterpriseLabel()
        eval($tag.equals("A级公司") || $tag.equals("HK上市") || $tag.equals("NewHighTec企业")
            || $tag.equals("NewThree板") || $tag.equals("Treminal上市") || $tag.equals("Stop上市"))
    then
        LabelResultVO rer = new LabelResultVO();
        rer.setRuleName("Enterprise_label");
        rer.setLabel($info.getEnterpriseLabel());
        $info.getResults().add(rer);
end

这段代码是使用 Drools 规则引擎 来实现业务规则的动态执行。它的核心逻辑是:从数据库中加载一些预定义的规则(DRL 文件格式),然后通过 Drools 构建一个规则执行环境,将传入的参数进行规则匹配和执行,并返回符合条件的结果。

我们可以把整个流程分为两部分来分析:


一、Java 主程序逻辑解释

1. 获取模板规则列表

List<TemplateRule> rules = templateRuleService.selectList(new TemplateRuleQueryParam(ModuleTypeEnum.TAG));
  • 调用 templateRuleService.selectList(...) 方法,根据模块类型(TAG)查询出一组规则。
  • 每个 TemplateRule 对象包含一个规则内容字段(content),通常是 DRL 格式的规则字符串。
  • 示例:你可能在数据库里存储了多个规则文件的内容。

2. 判断是否获取到规则

if (CollectionUtils.isEmpty(templateRules)) {
    log.error("获取规则异常");
    return null;
}
  • 如果没有查到任何规则,记录日志并返回空值,避免后续空指针错误。

3. 使用 KieHelper 构建规则引擎会话

KieHelper helper = new KieHelper();
templateRules.forEach(droolsRule -> helper.addContent(droolsRule.getContent(), ResourceType.DRL));
KieSession ksession = helper.build().newKieSession();
  • 创建 Drools 的 KieHelper 工具类,用于构建规则引擎。
  • 遍历所有 templateRules,将每个规则内容添加到 KieHelper 中。
  • 最终调用 helper.build() 构建出一个可以运行的规则会话(KieSession)。

4. 插入事实对象并执行规则

ksession.insert(param);
ksession.fireAllRules();
ksession.dispose();
  • 将外部传入的 param(如业务数据)插入到规则上下文中,作为“事实”供规则判断。
  • fireAllRules() 会触发所有满足条件的规则执行。
  • 执行完成后释放资源(dispose())。

5. 返回结果

return covert(param.getResults());
  • 假设 param 是一个包含 results 字段的对象,这个字段会被规则修改或填充。
  • 最后将其转换为最终返回结果(covert(...) 应该是 convert(...) 的拼写错误)。

二、DRL 规则文件内容解析

这是你的规则文件(以 DRL 格式编写):

package rules;

import com.platform.**.param.LabelParam;
import com.platform.**.vo.LabelResultVO;

rule "Enterprise Label"
    when
        $info : LabelParam(enterpriseLabel != null)
        $tag : String() from $info.getEnterpriseLabel()
        eval($tag.equals("AAA") || $tag.equals("BBB") || $tag.equals("CCC")
            || $tag.equals("DDD") || $tag.equals("EEE") || $tag.equals("FFF"))
    then
        LabelResultVO rer = new LabelResultVO();
        rer.setRuleName("Enterprise_label");
        rer.setLabel($info.getEnterpriseLabel());
        $info.getResults().add(rer);
end

解释如下:

1. 包声明和导入

package rules;

import com.platform.**.param.InfoLabelParam;
import com.platform.**.vo.LabelResultVO;
  • 定义规则包名为 rules
  • 导入需要用到的 Java 类型,用于在规则中使用这些类。

2. 规则名称

rule "Enterprise Label"
  • 规则的名字,便于识别和调试。

3. 条件部分(when)

$info : LabelParam(enterpriseLabel != null)
$tag : String() from $info.getEnterpriseLabel()
eval($tag.equals("AAA") || ... )
  • $info 是一个 InfoLabelParam 类型的事实对象,且其 enterpriseLabel 不为空。
  • $tag 是从 $info.getEnterpriseLabel() 中提取出来的字符串。
  • eval(...) 表示对这个字符串进行条件判断,如果标签是预定义的几种类型之一,则条件成立。

4. 动作部分(then)

LabelResultVO rer = new LabelResultVO();
rer.setRuleName("Enterprise_label");
rer.setLabel($info.getEnterpriseLabel());
$info.getResults().add(rer);
  • 创建一个 LabelResultVO 对象,设置规则名和匹配的标签。
  • 把这个结果加入到 $info.getResults() 列表中,供后续返回使用。

三、整体流程总结

步骤内容
1从数据库中读取一组规则(DRL 格式)。
2使用 Drools 的 KieHelper 加载这些规则内容。
3构建 KieSession 并插入传入的参数(即事实对象 param)。
4执行规则引擎,匹配并执行符合条件的规则。
5收集规则执行后的结果,返回给调用者。

四、适用场景举例

这种设计适用于以下场景:

  • 大量业务规则需要灵活配置,不希望硬编码在 Java 代码中;
  • 规则频繁变更,但不想每次修改都重新部署系统;
  • 需要集中管理规则,例如通过数据库或 UI 界面维护规则内容;
  • 规则之间存在复杂依赖关系,适合使用规则引擎来处理。

五、优化建议

  1. 规则缓存:如果你的规则不会频繁变化,可以考虑缓存 KieSessionKieBase,避免每次构建浪费性能。
  2. 规则热更新:可以通过监听数据库变化或使用 ZooKeeper/Redis 等机制实现规则热更新。
  3. 规则分组与优先级:可以在规则中添加 agenda-groupactivation-group 控制执行顺序。
  4. 异常处理:建议在规则执行过程中增加 try-catch 和日志记录,防止规则错误导致整个流程中断。