Easy Rules规则引擎(1-基础篇)
目录
- 一、序言
- 二、Easy Rules介绍
- 三、定义规则(Rules)
- 1、规则介绍
- 2、编程式规则定义
- 3、声明式规则定义
- 四、定义事实(Facts)
- 五、定义规则引擎(Rules Engine)
- 1、规则引擎介绍
- 2、InferenceRulesEngine规则引擎示例
- (1) 定义触发条件
- (2) 定义规则触发后的执行行为
- (3) 测试用例
一、序言
最近团队在做一些Visa、Master卡的交易风控,运营团队提供了一些交易风控的规则,比如针对卡号MCC设置单笔交易限额,24小时交易限额,72小时交易限额等等,还有触发风控规则是否拦截交易还是只发告警邮件等等等。
虽然写各种条件判断也能实现,但是随着后面规则增加,维护成本也会越来越高,所以想尝试引入规则引擎,同时考虑到开发和学习成本,还是决定学习轻量级的Easy Rules。
二、Easy Rules介绍
Easy Rules是一个Java规则引擎,它提供了规则抽象,通过触发条件和触发后的行为去创建规则。还提供了规则引擎API,通过这些API可以基于一系列的规则去判断规则是否触发,以及触发后执行什么动作。
核心特性:
- 轻量级Java库,易于学习的API。
- 注解式编程模型实现基于POJO开发。
- 通过抽象定义业务规则并且轻松应用规则。
- 支持通过简单规则可以创建组合规则。
- 支持通过表达式语言
(MVEL、SPEL和JEXL)定义规则。
相关依赖如下:
<!--Easy Rule-->
<!--核心库--><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.1.0</version></dependency><!--组合规则支持--><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-support</artifactId><version>4.1.0</version></dependency><!--SPEL表达式语言支持--><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-spel</artifactId><version>4.1.0</version>
</dependency><!--MVEL表达式语言支持-->
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-mvel</artifactId><version>4.1.0</version>
</dependency>
三、定义规则(Rules)
1、规则介绍
大多数的业务规则可以通过如下定义来描述:
- Name:唯一的规则名称。
- Description:简单规则描述。
- Priority:规则执行优先级。
- Facts:触发规则时的一系列事实。
- Condition:给定事实后,应该被满足的一系列条件。
- Actions:条件满足时应该执行的一系列行为。
Easy Rules中的规则由Rule接口来代表,如下:
public interface Rule extends Comparable<Rule> {/*** 判断规则是否应该被触发,true-是,false-否*/boolean evaluate(Facts facts);/*** 规则触发后执行的行为* @throws Exception 执行时触发的异常*/void execute(Facts facts) throws Exception;
}
2、编程式规则定义
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;/*** 编程式规则定义* @author Nick Liu* @date 2023/8/3*/
public class ProgrammaticHelloWorldRule implements Rule {@Overridepublic boolean evaluate(Facts facts) {return facts.get("enabled");}@Overridepublic void execute(Facts facts) throws Exception {System.out.println("Hello World");}@Overridepublic int compareTo(Rule o) {return 0;}public static void main(String[] args) {// 定义事实Facts facts = new Facts();facts.put("enabled", true);// 注册编程式规则Rules rules = new Rules();rules.register(new ProgrammaticHelloWorldRule());// 使用默认规则引擎根据事实触发规则RulesEngine rulesEngine = new DefaultRulesEngine();rulesEngine.fire(rules, facts);}
}
备注:运行程序控制台会输出
Hello World。
3、声明式规则定义
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;/*** 声明式规则定义* @author Nick Liu* @date 2023/8/3*/
@Rule(name = "Hello world rule", description = "Always say hello world")
public class DeclarativeHelloWorldRule {@Conditionpublic boolean when(@Fact("enabled") boolean enabled) {return enabled;}@Action(order = 1)public void then(@Fact("enabled") boolean enabled) throws Exception {System.out.println("Hello World");}@Action(order = 2)public void finalAction(Facts facts) throws Exception {System.out.println("Final Hello World");}public static void main(String[] args) {Facts facts = new Facts();facts.put("enabled", true);Rules rules = new Rules();rules.register(new DeclarativeHelloWorldRule());RulesEngine rulesEngine = new DefaultRulesEngine();rulesEngine.fire(rules, facts);}
}
控制台运行结果如下:
Hello World
Final Hello World
四、定义事实(Facts)
在Easy Rules中,事实由Fact类来定义,如下:
public class Fact<T> {private final String name;private final T value;
}
事实有name和value两个属性,两者都不能为空,且name属性值充当命名空间的角色需要唯一。
下面是定义事实的例子:
- 第1种方式
Fact<String> fact = new Fact("foo", "bar");
Facts facts = new Facts();
facts.add(fact);
- 第2种方式
Facts facts = new Facts();
facts.put("foo", "bar");
备注:两者方式都定义了一个name为foo,value为bar的事实实例,第二种方式更加简洁。
五、定义规则引擎(Rules Engine)
1、规则引擎介绍
Easy Rules提供了两种规则引擎的实现:
- DefaultRulesEngine:默认规则引擎,根据规则的自然顺序(默认为优先级)应用规则。
- InferenceRulesEngine:推理规则引擎,持续性应用单条规则,直到规则触发条件不满足。
Easy Rules规则引擎支持下面参数配置:
| 参数名称 | 参数类型 | 必选 | 默认值 |
|---|---|---|---|
| rulePriorityThreshold | int | 否 | Integer.MAX_VALUE |
| skipOnFirstAppliedRule | boolean | 否 | false |
| skipOnFirstFailedRule | boolean | 否 | false |
| skipOnFirstNonTriggeredRule | boolean | 否 | false |
skipOnFirstAppliedRule: 当规则被触发并且成功执行行为后是否跳过下条规则。skipOnFirstFailedRule: 当判断规则是否触发抛出异常或者触发成功但行为执行后抛出异常是否跳过下条规则。skipOnFirstNonTriggeredRule: 当规则未被触发是否跳过下条规则。rulePriorityThreshold: 如果规则优先级超过默认阈值,则跳过下条规则。
参数配置示例如下:
RulesEngineParameters parameters = new RulesEngineParameters().rulePriorityThreshold(10).skipOnFirstAppliedRule(true).skipOnFirstFailedRule(true).skipOnFirstNonTriggeredRule(true);RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
通过下面的代码可以获取规则引擎参数:
RulesEngineParameters parameters = myEngine.getParameters();
2、InferenceRulesEngine规则引擎示例
DefaultRulesEngine默认规则引擎的使用示例前面已经有提到过,下面我们看下InferenceRulesEngine推理规则引擎的代码示例。
(1) 定义触发条件
import org.jeasy.rules.api.Condition;
import org.jeasy.rules.api.Facts;/*** @author Nick Liu* @date 2023/8/5*/
public class HighTemperatureCondition implements Condition {@Overridepublic boolean evaluate(Facts facts) {int temperature = facts.get("temperature");return temperature > 25;}
}
(2) 定义规则触发后的执行行为
import org.jeasy.rules.api.Action;
import org.jeasy.rules.api.Facts;/*** @author Nick Liu* @date 2023/8/5*/
public class DecreaseTemperatureAction implements Action {@Overridepublic void execute(Facts facts) throws Exception {int temperature = facts.get("temperature");System.out.printf("Current temperature: %d, It's hot! cooling air...%n", temperature);facts.put("temperature", temperature - 1);}
}
(3) 测试用例
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.InferenceRulesEngine;
import org.jeasy.rules.core.RuleBuilder;/*** @author Nick Liu* @date 2023/8/5*/
public class AirConditionLauncher {public static void main(String[] args) {Facts facts = new Facts();facts.put("temperature", 30);// 通过规则构建API定义规则Rule rule = new RuleBuilder().name("Air Condition Rule").when(new HighTemperatureCondition()).then(new DecreaseTemperatureAction()).build();Rules rules = new Rules();rules.register(rule);// 基于事实重复应用规则的推理规则引擎,直到规则不再满足RulesEngine rulesEngine = new InferenceRulesEngine();rulesEngine.fire(rules, facts);}
}
控制台输出结果如下:
Current temperature: 30, It's hot! cooling air...
Current temperature: 29, It's hot! cooling air...
Current temperature: 28, It's hot! cooling air...
Current temperature: 27, It's hot! cooling air...
Current temperature: 26, It's hot! cooling air...
备注:可以看到定义的规则会持续触发,直到
temperature的值为25。

相关文章:
Easy Rules规则引擎(1-基础篇)
目录 一、序言二、Easy Rules介绍三、定义规则(Rules)1、规则介绍2、编程式规则定义3、声明式规则定义 四、定义事实(Facts)五、定义规则引擎(Rules Engine)1、规则引擎介绍2、InferenceRulesEngine规则引擎示例(1) 定义触发条件(2) 定义规则触发后的执行行为(3) 测试用例 一、…...
Linux 上安装部署Nacos
标题:在Linux上安装和部署Nacos Nacos是一个开源的分布式服务发现和配置管理平台,它可以帮助开发人员实现微服务架构中的服务注册、发现和动态配置管理。 步骤1:准备工作 在开始安装Nacos之前,确保您已经具备以下条件࿱…...
电动机的启动
1电动机启动分类 电动机启动方式包括:全压直接启动、自耦减压启动、Y-Δ 启动、软启动器、变频器。其中软启动器和变频器启动为潮流。当然也不是一定要使用软启动器和变频器启动,在运用的时候根据实际情况,从经济和适用性自行考虑选择。 2电…...
python性能分析,logging性能,print性能,文件写入性能对比
先说结论,没想到的是print性能比logging性能好,输出到控制台会极大降低程序性能,以下是我的性能对比结果: 运行情况是python后台运行并输出到日志,命令是 python3 test.py > /opt/testtime.log 2>&1 &...
[GIN-debug] [ERROR] listen tcp: address 8080: missing port in address
学习Golang_gin框架的第一天 遇到一下报错 : [GIN-debug] [ERROR] listen tcp: address 8080: missing port in address 错误代码 : package mainimport "github.com/gin-gonic/gin"func main() {router : gin.Default()router.GET("/index", func…...
PHP codeigniter4 搭配Nginx
> 主要是为了用Nginx运行PHP环境 1. Nginx 官方文档的配置 default.conf This configuration enables URLs without “index.php” in them and using CodeIgniter’s “404 - File Not Found” for URLs ending with “.php”. server {listen 80;listen [::]:80;se…...
AWS——04篇(AWS之Amazon S3(云中可扩展存储)-02——EC2访问S3存储桶)
AWS——04篇(AWS之Amazon S3(云中可扩展存储)-02——EC2访问S3存储桶) 1. 前言2. 创建EC2实例 S3存储桶3. 创建IAM角色4. 修改EC2的IAM 角色5. 连接EC2查看效果5.1 连接EC25.2 简单测试5.2.1 查看桶内存储情况5.2.2 复制本地文件…...
.netcore下grpc概述
一、什么是grpc 是一种与语言无关的高性能远程过程调用 (RPC) 框架。基于http/2标准设计,提供了头部压缩、tcp连接上的多路复用、流量控制、流式处理(客户端流/服务端流/双向流)。提供统一使用的.proto文件,它定义 grpc 服务和消…...
Address already in use
netstat -tunllp netstat -tunllp 命令是用来查看系统上所有的网络连接和监听端口,包括 TCP 和 UDP 连接。这个命令的选项含义如下: -t: 显示 TCP 连接-u: 显示 UDP 连接-n: 不进行主机名和服务名的解析,直接显示数字形式的 IP 地址和端口号…...
♥ vue中$set用法详细讲解
♥ vue中$set用法详细讲解 1、认识 在vue中,并不是任何时候数据都是双向绑定的。 官方文档介绍 使用场景 当数据没有被双向绑定的时候,我们就需要使用set了 举个例子: vue的data里边声明或者已经赋值过的对象或者数组(数组里…...
岩土工程仪器多通道振弦传感器信号转换器应用于桥梁安全监测
岩土工程仪器多通道振弦传感器信号转换器应用于桥梁安全监测 桥梁作为交通运输的重要节点,其安全性一直备受关注。不同于其他建筑物,桥梁所处的环境复杂多变,同时,其所需承受的负荷也相对较大,这就需要对桥梁的安全进…...
企业权限管理(六)-订单详情
订单详情查询 跳转到订单详情页面orders-show.jsp <button type"button" class"btn bg-olive btn-xs" onclick"location.href${pageContext.request.contextPath}/orders/findById.do?id${orders.id}">详情</button>OrdersControl…...
基于Tars高并发IM系统的设计与实现-实战篇5
基于Tars高并发IM系统的设计与实现-实战篇5 群聊服务 GroupChatServer 群聊服务既可以接受来自BrokerServer的用户请求,也需要接收来自其他服务的RPC请求;所以本服务提供两套RPC接口:通用RPC接口和专用RPC接口。 通用RPC接口 通用RPC接口主要处理如下…...
水溶性Cyanine3 N3叠氮化物Cy3 azide星戈瑞
欢迎来到星戈瑞荧光stargraydye! ICG-DBCO点击化学反应在生物标记物探测中应用。通过将ICG-DBCO与具有炔基的生物标记物结合,可以实现快速、选择性和稳定的共价连接,从而实现生物标记和探测。 **以下是ICG-DBCO点击化学反应在生物标记物探测中的一些应用…...
客户案例 | 永续发展,低代码助力“双碳”战略历史使命
关键发现 客户痛点:应对企业数字化转型,新技术能否提升绩效的不确定性,投资带来的风险性,以及企业组织架构的适应性等难点问题。作为业务驱动型企业,欠缺快速构建数字化产品方案的能力。 解决方案:利用西门…...
[保研/考研机试] KY187 二进制数 北京邮电大学复试上机题 C++实现
描述 大家都知道,数据在计算机里中存储是以二进制的形式存储的。 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的。 你能帮帮小明吗?并且,小…...
SpringBoot 热部署
一、启动热部署 1.1 开启开发者工具 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional> </dependency>…...
BLE蓝牙协议栈分析
BLE——协议层次结构 一、BLE Controller Controller实现射频相关的模拟和数字部分,完成最基本的数据发送和接收,Controller对外接口是天线,对内接口是主机控制器接口HCI(Hostcontroller interface); 控制…...
flutter开发实战-BackdropFilter高斯模糊子Widget控件
flutter开发实战-BackdropFilter高斯模糊子Widget。 最近开发过程中遇到需要将控件进行模糊,比如iOS的effect的模糊效果。那在flutter中就需要用到了BackdropFilter 一、BackdropFilter BackdropFilter属性定义 BackdropFilter({Key key, required ImageFilter …...
嵌入式面试刷题(day3)
文章目录 前言一、怎么判断两个float是否相同二、float数据可以移位吗三、数据接收和发送端大小端不一致怎么办四、怎么传输float类型数据1.使用联合进行传输2.使用字节流3.强制类型转换 总结 前言 本篇文章我们继续讲解嵌入式面试刷题,给大家继续分享嵌入式中的面…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
