一、背景
在之前分享的文章中,我介绍了sql-analysis这个京东开源的慢SQL组件源码设计和原理,在分析的过程中,我们知道了它使用了开源的规则引擎EasyRule进行SQL结果的动态分析比较,从而实现了规则的动态维护业务的规则判断。
在介绍之前,我们先来看看这个程序员的故事:
从前有个程序员小李,刚入职一家互联网公司。公司业务复杂,需求变化比女朋友心情还快。一会儿说折扣规则改一下,满100减20;一会儿又说换成买三送一,还要根据用户等级定折扣比例。产品经理小张的需求文档从来没有最复杂,只有更复杂。
于是小李开始干活了。
第一天:手写逻辑的“狂野生涯”
小李撸起袖子开始写代码,用 if-else 实现折扣规则:
if (userLevel == "VIP") {
if (totalAmount > 100) {
discount = 20;
} else {
discount = 10;
}
} else {
discount = 5;
}
小李美滋滋地以为搞定了,没想到第二天产品经理来了句:“再加个新用户首单 50% 折扣规则。”
小李叹了口气,又加了一大堆 if-else。
第一百天:代码成了“噩梦森林”
100天后,小李的折扣逻辑已经长成了一个庞大的“迷宫”:
if (userLevel == "VIP" && isFirstOrder && totalAmount > 100) {
// 一堆逻辑
}
else if (...) {
// 又一堆逻辑
}
else if (...) {
// 更复杂的逻辑
}
代码没人敢动,测试小姐姐一改配置就崩,小李的发际线肉眼可见地后移。连产品经理都忍不住说:“你这代码比我大学数学考试的步骤还难懂啊!”
一天,小李发现了“规则引擎”
就在小李绝望的时候,资深架构师老王拍拍他的肩膀:“小伙子,听说过规则引擎吗?”
“规则引擎?这能吃吗?”
老王笑了:“它可比外卖有用得多。规则引擎就像个聪明的裁判,专门处理这种繁琐、动态的业务规则。只需要定义规则条件和动作,改需求的时候直接改规则配置,代码几乎不用动。”
规则引擎拯救世界
小李抱着试一试的心态,接入了一个开源的规则引擎——比如 EasyRules。一个复杂的业务需求变成了简单的规则配置:
- name: "VIP满100减20"
condition: "user.level == 'VIP' && totalAmount > 100"
action: "discount = 20"- name: "新用户首单50%折扣"
condition: "user.isFirstOrder == true"
action: "discount = totalAmount * 0.5"
产品经理惊呼:“改规则不用找你改代码了?!”
测试小姐姐:“规则清晰多了,测试也简单了!”
小李终于可以准时下班了,他的发际线也开始神奇地恢复了。
结局:规则引擎带来的新生活
小李深有感触地总结:“规则引擎,拯救发际线,提升生产力!”
从此,凡是复杂业务逻辑,他都用上了规则引擎,再也没写过乱七八糟的 if-else。
用规则引擎管理复杂规则,就像从“手工种田”迈向了“工业化生产”,它让规则管理更灵活,开发更轻松,团队更和谐。程序员朋友们,再不学规则引擎,你的代码可能就要“变森林”了哦!
本文开始分享的规则引擎京东慢SQL组件中使用到的规则引擎:EasyRules。
EasyRules 是一个轻量级且易于学习的Java规则引擎,它提供了一个简单的方式来定义业务规则,并在Java应用中轻松应用这些规则,组件设计的灵感来源于马丁·福勒的一篇文章,Easy
Rules旨在帮助开发者以POJO的形式构建规则,并通过条件和动作进行表达。
二、规则引擎知识
首先我来分享下规则引擎的一些知识。
规则引擎描述
规则引擎是一种将业务规则与业务逻辑分离的技术,它可以将复杂的业务规则表示为一组简单的规则,并通过规则引擎来执行这些规则。规则引擎可以提高业务规则的可维护性、可扩展性和可重用性,同时也可以提高业务系统的灵活性和响应能力。
规则引擎的优点
- 灵活性:规则引擎可以灵活地定义和修改业务规则,不需要修改业务系统的代码。这种灵活性使得规则引擎能够快速响应业务需求的变化,减少了对业务系统的影响。
- 可维护性:规则引擎将业务规则与业务系统分离,便于维护和管理。规则引擎的独立设计使得规则可以独立于业务系统进行维护和更新,降低了业务系统的复杂性。
- 高效性:规则引擎可以自动执行规则,减少人工干预,提高业务效率。规则引擎的自动化处理能力能够快速、准确地执行业务规则,提高了业务流程的执行效率。
- 可扩展性:规则引擎可以方便地扩展和添加新的规则,适应业务的变化。规则引擎的模块化设计使得规则可以灵活地组合和扩展,满足不同业务场景的需求。
- 增强决策能力:规则引擎支持复杂的决策逻辑,能够处理大量的数据和规则。通过使用规则引擎,企业可以提高决策的准确性和效率,更好地应对复杂的业务环境。
规则引擎的应用场景
- 金融行业:规则引擎可以用于信用评估、风险管理、欺诈检测等。规则引擎能够根据客户的信用历史、交易行为等数据,快速评估客户的信用等级,识别欺诈行为,为金融机构提供决策支持。
- 电信行业:规则引擎可以用于计费、优惠策略、客户忠诚度管理等。规则引擎能够根据客户的通话记录、套餐使用情况等数据,自动计算费用,提供优惠方案,提高客户满意度和忠诚度。
- 电商行业:规则引擎可以用于订单处理、促销活动、库存管理等。规则引擎能够根据订单信息、商品库存情况等数据,自动处理订单,执行促销活动,优化库存管理。
- 医疗行业:规则引擎可以用于医疗保险理赔、医疗诊断、药品管理等。规则引擎能够根据患者的医疗记录、诊断结果等数据,快速进行理赔审核,提供准确的诊断建议,管理药品库存。
常见的规则引擎的
- 典型的风控场景
- 活动策略运营
- 数据类系统的分析和清洗
- 流程分支非常复杂,规则变量庞大;
- 有不确定性的需求,变更频率较高;
- 需要快速做出响应和决策;
- 规则变更期望脱离于开发人员,脱离coding。
- 满足XXX条件后执行XXX的内容。
- 业务规则管理:用于管理和维护复杂的业务规则,如保险理赔、贷款审批、订单处理等。
- 决策支持:用于支持企业的决策过程,如风险评估、信用评级、市场预测等。
- 数据验证:用于验证数据的合法性和完整性,如用户注册、订单提交等。
真实场景截图
截图1:这是一个通过在数据库中维护规则引擎表达式的使用场景,通过在数据库中维护规则表达式,从而实现某些Java业务逻辑的动态维护,这个设计是非常有用的:
截图2:这个是通过一个界面来维护规则的关系的规则引擎前端界面,通过在界面中指定多组条件之间的关系,从而形成一个执行的逻辑流程,这种界面和QueryBuilder的东西非常类似,页面的操作也是一定程度上的QueryBuilder的思想。
截图3:这是一个通过界面来维护规则的设计,可以指定每个规则的条件,多个条件形成了条件组,从而形成规则集等等,通过友好的界面拖动实现规则的在线维护等等。
截图4:
这是一个图形化规则引擎系统的维护界面,可以在界面中配置规则引擎的条件与节点关系,实现不同业务场景下的自定义业务流程的规则处理:
通过上面的几个截图,大家可能已经有了一些基本的认识,接下来看看组成部分.
三、规则引擎的组成
3.1、常见术语
先来看张图:
这张图表达式的是,将一些具备特征的数据,输入到规则引擎中,然后再规则引擎中,将特征值/属性作为条件的参数参与条件的执行中,如果条件满足了,则执行结果,多个规则之前通过串行、树结构等等关系实现规则的组合判断。
各项含义如下:
特征:用于作为判断条件的指标、比较值、变量等,特征值:规则配置的变量就是特征值,特征值的数据都来源于数据字典
条件:用于作为规则引擎的的核心判断方式,不同类型有不同的方式
规则:规则引擎里面的最基本的原子定义,支持一系列特征值的基础运算,包括与或运算。隶属于场景,可以被该场景下的所有规则集所引用
规则集:业务调用的基础单位,业务调用使用规则编码,支持多种执行策略,包括全部执行,命中退出,决策流等
决策流:将一系列规则以流的形式组合而成,规则集中的其中一个执行策略
场景:包含多个规则集和多个规则
数据字典:定义一系列类型数据,包括字符,布尔,数值,日期等,作为特征值的原始数据
如图所示:
3.2、常见的几种分类
在市面中,我们通常由如下4类的规则引擎,每类的使用场景稍微有些不同,但是都是符合规则引擎要达到的目标。
概念和区别如下:
1、表达式类规则引擎:核心关注点在于易变逻辑的抽离,通过表达式替换硬编码。
常见的:QLExpress、Aviator
参考资料:
2、规则类的规则引擎:是表达式引擎更上一层,核心关注点在于匹配,主要解决规则分散难以维护的问题。
常见的非常成熟的:Drools、urule、JVS-rules、EasyRule
URule Pro是一款由上海锐道信息技术有限公司自主研发的一款纯Java规则引擎,它可以运行在Windows、Linux、Unix等各种类型的操作系统之上;URule Pro的规则设计器采用业内首创的纯浏览器编辑模式,无须安装任何工具,打开浏览器即可完成复杂规则的设计与测试。
URule资料如下:www.bstek.com/resources/d…
3、决策类的规则引擎:是规则引擎更上一层,核心关注点在于判断,主要解决选择的问题。
规则集、决策树、决策矩阵、评分卡等
决策树也称规则树,是由多个规则按一定分支及流程编排而成,直观显示如下:
截图1:
4、流程类的规则引擎: 是表达式引擎或规则引擎之上,核心关注点在于整体的流程刘庄,主要解决流程节点分散管理不直观。
比如开源项目LiteFlow,就是属于这种流程类的规则引擎。
四、开源规则引擎EasyRule的使用
Easy Rules 是一个开源的、轻量级的 Java 规则引擎,它让我们能够用更优雅、清晰的方式定义和管理规则。Easy Rules 支持多种方式定义规则,包括注解、流式 API、表达式语言和 YAML 文件。
easy-rules的Github地址:github.com/j-easy/easy…
接下来我分享如何使用,来源与官方的Github仓库中的ReadME文档。
之前我说道规则引擎是一种能够基于规则自动决策的工具,而大部分我们接触到的规则通常是条件-动作的组合(即“如果...那么...”的逻辑),而规则引擎的任务就是根据输入的事实,检查规则的条件是否成立,然后执行相应的动作。在EasyRule中对相关的概念进行了抽象,所以作为第一次接触到规则引擎的小伙伴,拿EasyRule作为入门学习是不错的起点。
Easy Rules中抽象了几个概念:
Fact(事实):输入的数据,它们用于规则判断,说白了,就是参数。
Rule(规则):由条件和动作组成的业务逻辑,说白了,就是配置,每个配置里面有When逻辑和Then逻辑组成。
根据官方文档介绍,可以通过四种方式来定义规则。
Condition(条件):判断的业务,即When逻辑。
Action(动作):满足条件后的执行动作,即Then逻辑。
方法一:使用注解定义规则
最直接的方式是通过注解来定义规则。我们定义一个简单的天气规则——如果下雨,就带伞。
@Rule(name = "天气规则", description = "如果下雨,就带伞")
public class WeatherRule {
@Condition
public boolean itRains(@Fact("rain") boolean rain) {
// 如果 rain 为 true,表示下雨
return rain;
}
@Action
public void takeAnUmbrella() {
System.out.println("下雨了,请带伞"); // 如果下雨,打印提示
}
}
在这个例子中,@Rule 注解用于定义规则名称和描述,@Condition 注解定义了条件,而 @Action 注解定义了满足条件时要执行的动作。
方法二:使用流式 API 定义规则
如果你更喜欢代码驱动的方式,可以通过 Easy Rules 的流式 API 来定义规则:
import org.jeasy.rules.core.RuleBuilder;
Rule weatherRule = new RuleBuilder()
.name("天气规则")
.description("如果下雨就带伞")
.when(facts -> facts.get("rain").equals(true)) // 定义条件:rain 为 true
.then(facts -> System.out.println("下雨了带一个伞!")) // 定义动作
.build();
这种方式更适合那些喜欢通过编程方式构建规则的人,所有的规则定义都通过流式调用完成。
方法三:使用表达式语言(MVEL)
使用表达式语言 (MVEL) 可以让规则定义更加简洁。以下是使用 MVEL 语言定义的规则:
import org.jeasy.rules.mvel.MVELRule;
Rule weatherRule = new MVELRule()
.name("天气规则")
.description("如果下雨就带伞")
.when("rain == true") // 条件为 rain 等于 true
.then("System.out.println(\"下雨了,带一个伞\");"); // 动作为打印
方法四:使用规则描述符(YAML)
Easy Rules 还支持从外部文件加载规则描述,比如使用 YAML 文件:
# weather-rule.yml
name: "天气规则"
description: "如果下雨了就带伞"
condition: "rain == true"
actions:
- "System.out.println(\"如果下雨了就带伞!\");"
这种方式非常适合那些需要从配置文件动态加载规则的场景。如果之前理解了上篇文章中的慢SQL组件的设置,相信现在应该又理解了一遍。京东开源慢SQL组件的规则引擎代码如下:
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.api.Rule;
MVELRuleFactory ruleFactory = new MVELRuleFactory();
Rule weatherRule = ruleFactory.createRule(new FileReader("weather-rule.yml"));
这种方式非常适合那些需要从配置文件动态加载规则的场景。如果之前理解了上篇文章中的慢SQL组件的设置,相信现在应该又理解了一遍。京东开源慢SQL组件的规则引擎代码如下:
触发规则
在定义了规则之后,我们需要根据实际的事实(即输入数据)来触发规则执行。
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
public class Test {
public static void main(String[] args) {
// 定义事实
Facts facts = new Facts();
facts.put("rain", true); // 表示当前在下雨
// 定义规则(可以使用前面任意一种定义方式)
Rule weatherRule = ...;
// 注册规则
Rules rules = new Rules();
rules.register(weatherRule);
// 创建规则引擎并触发规则
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.fire(rules, facts); // 根据事实触发规则
}
}
在这个例子中,我们首先创建一个 Facts 对象,存储当前的输入数据(在这个例子里,rain 为 true,表示下雨),然后创建并注册规则,最后通过规则引擎根据事实执行满足条件的规则。规则成功地匹配了当前的事实,并执行了相应的动作。
通过这个例子,我们已经成功创建并触发了一个简单的规则。如果你需要处理更复杂的逻辑,Easy Rules 还提供了更多强大的功能,比如规则优先级、规则群组、条件组合等。
Easy Rules 提供了多种方式来定义和使用规则,无论是注解、流式 API、表达式语言还是外部配置文件,都能满足不同场景的需求。你可以根据你的项目需求选择最适合的方式。
在实际开发中,规则引擎可以帮助我们将复杂的业务逻辑进行解耦,提升代码的可读性和维护性。
希望通过本文的介绍,你已经对 Easy Rules 有了一个基本的了解,并能够在自己的项目中尝试使用它。
在这个项目的仓库中的代码,也提供了相应的例子:
在这里面我们经常使用到的注解如下:
@Rule注解: 规则的声明,作用于类上,说明是一个规则
@Condition注解:规则条件声明,作用于Rule中的一个方法上,返回值为布尔类型。
@Action注解:规则方法注解,当满足一个Rule条件时需要执行的方法,作用于方法。order属性满足条件时有多个方法,方法的执行顺序。值越小越先执行。
@Fact注解:参数注解,可作用于Condition和Rule的方法参数上。
@Priority注解:Rule优先级注解,作用在一个方法上,该方法返回integer类型的值作为rule的优先级。
为了能够让大家更好的理解,我用AI生成了一下EasyRule的前端可视化配置界面,效果如下所示:
可以在界面上配置规则基本信息,然后单击生成代码,可以生成代码样例:
我然后又让AI给我转换为Vue.js格式的代码,也是非常不错的:
AI还建议我生成如下功能:
- 条件组扩展:支持不同的逻辑组合(如 "或者" 组合条件)。
- 复杂条件支持:可以让用户在生成的条件表达式中插入括号,形成更复杂的逻辑表达式。
- 动作配置扩展:可以支持多种动作(如多行代码)或者条件触发不同动作。
- 保存配置:可以添加保存配置的功能,将用户配置的条件组和规则保存为文件或者发送到后端进行处理。
真的说,AI真的太强大了,程序员赶紧被淘汰吧。
这个之前写过了一篇文章进行分享:
五、总结
本文分享了关于规则引擎的业务知识、规则引擎的分类、EasyRule开源规则引擎的介绍,希望大家可以学会使用这个规则引擎,从而具备如何设计一种动态化的程序判断、一种基于规则的程序判断,从而设计出更佳解耦合的程序设计。