规则引擎代码: 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 界面维护规则内容;
- 规则之间存在复杂依赖关系,适合使用规则引擎来处理。
五、优化建议
- 规则缓存:如果你的规则不会频繁变化,可以考虑缓存
KieSession或KieBase,避免每次构建浪费性能。 - 规则热更新:可以通过监听数据库变化或使用 ZooKeeper/Redis 等机制实现规则热更新。
- 规则分组与优先级:可以在规则中添加
agenda-group或activation-group控制执行顺序。 - 异常处理:建议在规则执行过程中增加 try-catch 和日志记录,防止规则错误导致整个流程中断。