> 技术文档 > 【中间件】一文搞懂规则引擎 - Easy Rules_easy-rules

【中间件】一文搞懂规则引擎 - Easy Rules_easy-rules


规则引擎

规则引擎介绍

  规则引擎全称为业务规则管理系统,英⽂名为 BRMS(即 Business Rule Management System)。规则引擎的主要思想是将应用程序中的业务决策部分分离出来,并使用预定义的语义模块编写业务决策(业务规则),由用户或开发者在需要时进行配置、管理。 需要注意的是规则引擎并不是一个具体的技术框架,而是指的⼀类系统,即业务规则管理系统。​ 规则引擎实现了将业务决策从应用程序代码中分离出来,接收数据输入,解释业务规则,并根据业务规则做出业务决策。规则引擎其实就是一个输入输出的平台。
  规则引擎就是提供一种可选的计算模型。与通常的命令式模型(由带有条件和循环的命令依次组成)不同,规则引擎基于生产规则系统。这是一组生产规则,每条规则都有一个条件(condition)和一个动作(action)。简单地说,可以将其看作是一组 if-then 语句。目前市面上具体的规则引擎产品有:Drools、VisualRules、iLog 等,使用最为广泛并且开源的是 Drools。

规则引擎解决什么问题?

  • 硬编码实现业务规则难以维护
  • 硬编码实现业务规则难以应对变化
  • 业务规则发⽣变化需要修改代码,重启服务后才能生效

规则引擎优势

  • 业务规则与系统代码分离,实现业务规则的集中管理
  • 在不重启服务的情况下可随时对业务规则进行扩展和维护
  • 可以动态修改业务规则,从⽽快速响应需求变更
  • 规则引擎是相对独立的,只关心业务规则,使得业务分析⼈员也可以参与编辑、维护系统的业务规则
  • 减少了硬编码业务规则的成本和风险
  • 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单

【Easy Rules】

Easy Rules 介绍

  Easy Rules 是一个 Java 规则引擎。Easy Rules 它提供 Rule 抽象以创建具有条件和动作的规则,并提供 RuleEngine API,该 API 通过一组规则运行以评估条件并执行动作。

Easy Rules 概念

  • 规则(Rule): 规则是 EasyRules 框架中的核心概念,它用于描述应用程序中需要遵循的规则。每个规则通常包含两个部分:规则名称和规则条件。
  • 规则条件(Condition): 规则条件定义了规则的前提条件。如果规则条件为 true,则规则将被触发执行。否则,规则将被忽略。
  • 规则动作(Action): 规则动作是在规则被触发时执行的一段代码。它可以用于实现各种应用程序逻辑,例如更新数据、发送消息等。
  • 规则执行(Rule Engine): 规则执行是 EasyRules 框架的核心功能之一,它负责解析规则条件,并根据条件执行相应的规则动作。

【Easy Rules 入门案例】

SpringBoot 集成 Easy Rules

<dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-core</artifactId> <version>4.1.0</version></dependency><dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-mvel</artifactId> <version>4.1.0</version></dependency><dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-spel</artifactId> <version>4.1.0</version></dependency>
# ------------------------------------ 配置规则 ------------------------------------------name: \"无效加班\"description: \"加班费的结算\"priority: 1condition: \"time<=80\"actions: - \"reason.append(\'加班少于80小时,不发加班费;\');\"---name: \"有效加班\"description: \"加班费的结算\"priority: 2condition: \"time>80\"actions: - \"money=(money+10*(time-80));reason.append(\'加班费:\').append(10*(time-80)).append(\';\');\"---name: \"迟到警告\"description: \"迟到的惩罚\"priority: 1condition: \"count<=3\"actions: - \"reason.append(\'迟到小于3次,暂时不扣钱;\');\"---name: \"迟到扣钱\"description: \"迟到的惩罚\"priority: 2condition: \"count>3\"actions: - \"money=(money - (count-3)*1000);reason.append(\'迟到大于3次,扣钱:\').append((count - 3) * 1000).append(\';\');\"
// ------------------------------------ 测试代码 ---------------------------------------@GetMapping(\"/test\")public String test() throws Exception { // 配置规则引擎参数 RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(false); // 初始化规则引擎 RulesEngine engine = new DefaultRulesEngine(parameters); // 规则文件读取(通过配置文件方式配置规则) Rules rules = new MVELRuleFactory(new YamlRuleDefinitionReader()).createRules(new BufferedReader(new InputStreamReader(Objects.requireNonNull(this.getClass().getClassLoader().getResourceAsStream(\"rules.yml\"))))); // 创建事实对象 Facts facts = new Facts(); facts.put(\"money\", 1000); facts.put(\"time\", 900); facts.put(\"count\", 5); facts.put(\"reason\", new StringBuffer()); // 根据事实对象与规则,通过规则引擎进行执行 engine.fire(rules, facts); // 获取结果:加班费:8200;迟到大于3次,扣钱:2000; String reason = facts.get(\"reason\").toString(); return reason;}

【Easy Rules 定义规则方式】

方式一:注解

@Rule(name = \"weather rule\", description = \"if it rains then take an umbrella\")public class WeatherRule { @Condition public boolean itRains(@Fact(\"rain\") boolean rain) { return rain; } @Action(order = 1) public void takeAnUmbrella() { System.out.println(\"It rains, take an umbrella!\"); }}

方式二:链式编程

Rule weatherRule = new RuleBuilder() .name(\"weather rule\") .description(\"if it rains then take an umbrella\") .when(facts -> facts.get(\"rain\").equals(true)) .then(facts -> System.out.println(\"It rains, take an umbrella!\")) .build();

方式三:表达式

Rule weatherRule = new MVELRule() .name(\"weather rule\") .description(\"if it rains then take an umbrella\") .when(\"rain == true\") .then(\"System.out.println(\\\"It rains, take an umbrella!\\\");\");

方式四:yml 配置文件

name: \"weather rule\"description: \"if it rains then take an umbrella\"condition: \"rain == true\"actions: - \'System.out.println(\"It rains, take an umbrella!\");\'
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());Rule weatherRule = ruleFactory.createRule(new FileReader(\"weather-rule.yml\"));

方式五:json 文件

[ { \"name\": \"Weather Rule\", \"description\": \"If it rains, take an umbrella\", \"priority\": 1, \"condition\": \"facts[\'weather\'] == \'rainy\'\", \"actions\": [\"System.out.println(\'It rains, take an umbrella!\')\"] }]
import org.jeasy.rules.api.Facts;import org.jeasy.rules.core.DefaultRulesEngine;import org.jeasy.rules.mvel.MVELRule;import org.jeasy.rules.support.reader.JsonRuleDefinitionReader;import org.jeasy.rules.support.reader.RuleDefinitionReader;import java.io.FileReader;import java.util.List;public class DynamicRuleExample { public static void main(String[] args) throws Exception { // 读取 JSON 文件 RuleDefinitionReader reader = new JsonRuleDefinitionReader(); List<MVELRule> rules = reader.read(new FileReader(\"rules.json\")); // 定义事实 Facts facts = new Facts(); facts.put(\"weather\", \"rainy\"); // 加载规则并执行 DefaultRulesEngine rulesEngine = new DefaultRulesEngine(); rulesEngine.fire(new org.jeasy.rules.api.Rules(rules), facts); }}

【Easy Rules 详解】

引擎配置参数

  在配置规则引擎初始化参数的时候可以设置引擎的其他参数。

  • rulePriorityThreshold: 整型,当优先级超过指定的阈值时,跳过余下的规则。
  • skipOnFirstAppliedRule: 布尔类型,当一个规则成功应用时,跳过余下的规则。
  • skipOnFirstFailedRule: 布尔类型,当一个规则失败时,跳过余下的规则。
  • skipOnFirstNonTriggeredRule: 布尔类型,当一个规则未触发时,跳过余下的规则。
// 配置规则引擎参数RulesEngineParameters parameters = new RulesEngineParameters();parameters.priorityThreshold(10);parameters.setSkipOnFirstAppliedRule(true);parameters.setSkipOnFirstFailedRule(true);parameters.setSkipOnFirstNonTriggeredRule(true);

规则定义参数

  无论以那种方式进行代码的编写,最终实现的都是需要定义如下几个参数,通过不同的参数对规则进行描述。

  • Name: 一个命名空间下的唯一的规则名称【对应代码中的 then() 与 @Rule 中 name 属性】
  • Description: 规则的简要描述(非必填)【对应代码中的 then() 与 @Rule 中 description 属性】
  • Priority: 相对于其他规则的优先级,默认优先级为 Integer.MAX_VALUE,值越小,优先级越高。【对应代码中的@Actions 中 order 属性】
  • Conditions: 为了应用规则而必须满足的一组条件【对应代码中的 when() 与 @Condition 】
  • Actions: 当条件满足时执行的一组动作【对应代码中的 then() 与 @Actions 】
  • Facts: 事实,可理解为要处理的数据。

【Easy Rules 监听器】

Easy Rules 监听器

  在 Easy Rules 中,有 RulesEngineListener 和 RuleListener 两种不同粒度的监听器,用于监控规则引擎的运行过程。它们的核心区别在于监听范围和触发时机

注入监听器

  在创建规则引擎之后可以通过对应的属性注入 RuleListener 和 RulesEngineListener。

// 配置规则引擎参数RulesEngineParameters parameters = new RulesEngineParameters();// 初始化规则引擎DefaultRulesEngine engine = new DefaultRulesEngine(parameters);// 创建自定义的RuleListenerIMoMeiRuleListener iMoMeiRuleListener = new IMoMeiRuleListener();// 创建自定义的RulesEngineListenerIMoMeiRulesEngineListener iMoMeiRulesEngineListener = new IMoMeiRulesEngineListener();// 配置RuleListenerengine.registerRuleListeners(List.of(iMoMeiRuleListener));// 配置RulesEngineListenerengine.registerRulesEngineListeners(List.of(iMoMeiRulesEngineListener));

RuleListener 规则监听器

  • 作用对象: 单个规则的执行过程
  • 主要用途: 监听单个规则的评估(evaluate)和执行(execute)生命周期
  • 常用场景:
    • 记录单个规则的执行耗时
    • 处理规则执行时的异常
    • 根据条件跳过特定规则的执行
    • 统计规则命中率
// ---------------------------------- 规则监听器接口 -----------------------------------public interface RuleListener { /** * 规则匹配前(所有场景都会进) * * @param rule 规则 * @param facts 事实 * @return */ default boolean beforeEvaluate(Rule rule, Facts facts) { return true; } /** * 规则匹配后(所有场景都会进) * * @param rule 规则 * @param facts 事实 * @param evaluationResult 匹配结果 */ default void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) { } /** * 规则匹配异常 * * @param rule 规则 * @param facts 事实 * @param exception 异常信息 */ default void onEvaluationError(Rule rule, Facts facts, Exception exception) { } /** * 规则执行前(需要规则匹配) * * @param rule 规则 * @param facts 事实 */ default void beforeExecute(Rule rule, Facts facts) { } /** * 规则执行成功 * * @param rule 规则 * @param facts 事实 */ default void onSuccess(Rule rule, Facts facts) { } /** * 规则执行失败 * * @param rule 规则 * @param facts 事实 * @param exception 异常信息 */ default void onFailure(Rule rule, Facts facts, Exception exception) { }}

RulesEngineListener 引擎监听器

  • 作用对象: 整个规则引擎的执行流程
  • 主要用途: 监听整个引擎的执行过程(例如所有规则的检查、执行顺序)
  • 常用场景:
    • 记录引擎整体执行时间
    • 监控规则执行的整体成功率
    • 在引擎执行前后进行资源初始化和清理
    • 控制规则执行流程(如提前终止)
// ---------------------------------- 引擎监听器接口 -----------------------------------public interface RulesEngineListener { /** * 在执行规则集之前触发 * * @param rules 要触发的规则集 * @param facts 触发规则前的事实 */ default void beforeEvaluate(Rules rules, Facts facts) { } /** * 在执行规则集之后触发 * * @param rules 要触发的规则集 * @param facts 触发规则前的事实 */ default void afterExecute(Rules rules, Facts facts) { }}

【Easy Rules 高级用法】PS:后续补充

规则链

正向链式触发

反向链式触发

异步规则执行

​ 与 Spring Boot 集成

动态规则加载与热更新

百科名医视频网