Easy Rules规则引擎(1-基础篇)

news2024/9/26 5:19:17

目录

  • 一、序言
  • 二、Easy Rules介绍
  • 三、定义规则(Rules)
    • 1、规则介绍
    • 2、编程式规则定义
    • 3、声明式规则定义
  • 四、定义事实(Facts)
  • 五、定义规则引擎(Rules Engine)
    • 1、规则引擎介绍
    • 2、InferenceRulesEngine规则引擎示例
      • (1) 定义触发条件
      • (2) 定义规则触发后的执行行为
      • (3) 测试用例

一、序言

最近团队在做一些VisaMaster卡的交易风控,运营团队提供了一些交易风控的规则,比如针对卡号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 {

	@Override
	public boolean evaluate(Facts facts) {
		return facts.get("enabled");
	}

	@Override
	public void execute(Facts facts) throws Exception {
		System.out.println("Hello World");
	}

	@Override
	public 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 {

	@Condition
	public 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;
}

事实有namevalue两个属性,两者都不能为空,且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");

备注:两者方式都定义了一个namefoovaluebar的事实实例,第二种方式更加简洁。


五、定义规则引擎(Rules Engine)

1、规则引擎介绍

Easy Rules提供了两种规则引擎的实现:

  • DefaultRulesEngine:默认规则引擎,根据规则的自然顺序(默认为优先级)应用规则。
  • InferenceRulesEngine:推理规则引擎,持续性应用单条规则,直到规则触发条件不满足。

Easy Rules规则引擎支持下面参数配置:

参数名称参数类型必选默认值
rulePriorityThresholdintInteger.MAX_VALUE
skipOnFirstAppliedRulebooleanfalse
skipOnFirstFailedRulebooleanfalse
skipOnFirstNonTriggeredRulebooleanfalse
  • 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 {

	@Override
	public 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 {

	@Override
	public 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。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/853899.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能安防监控:基于Java+SpringBoot实现人脸识别搜索

目录 引言背景介绍目的和重要性 人脸识别技术的基本原理图像采集和预处理特征提取与表示人脸匹配算法 人脸识别搜索的应用领域公告安全和监控社交网络和照片管理 参考实现步骤数据收集与预处理人脸特征提取查询处理 引言 背景介绍 结合人脸识别技术&#xff0c;在工厂、学校、…

【Docker】AUFS、BTRFS、ZFS、储存池详解

洁洁的个人主页 我就问你有没有发挥&#xff01; 知行合一&#xff0c;志存高远。 前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是…

2023/08/09 IOS设计规范收集

背景&#xff1a;绘制原型图时&#xff0c;不确定状态栏、标签栏、侧边margin具体怎么设置&#xff0c;很困惑… iphone 界面尺寸 左边是能找到最新的设计规范&#xff0c;右边是auxre10自带画布尺寸显示&#xff0c;结合做参考 ios界面结构 状态栏 状态栏位于界面最上方&…

Leetcode-每日一题【剑指 Offer 18. 删除链表的节点】

题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 注意&#xff1a;此题对比原题有改动 示例 1: 输入: head [4,5,1,9], val 5输出: [4,1,9]解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么在调…

竞争加剧,毛利率低于竞争对手,京东前路艰难

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 机遇与风险 虽然京东&#xff08;JD&#xff09;与亚马逊&#xff08;AMZN&#xff09;在业务方面有很多相似的地方&#xff0c;但两家公司在毛利率方面却有很大的差异。长期以来&#xff0c;亚马逊的利润率一直接近40%甚至…

模板学堂|SQL数据集动态参数使用场景及功能详解

DataEase开源数据可视化分析平台于2022年6月正式发布模板市场&#xff08;https&#xff1a;//dataease.io/templates/&#xff09;。模板市场旨在为DataEase用户提供专业、美观、拿来即用的仪表板模板&#xff0c;方便用户根据自身的业务需求和使用场景选择对应的仪表板模板&a…

CD4029计数器实测仿真及BCD转七段码

前面的博文中&#xff0c;我们介绍过CD40110(这是一个常见的直接接7段数码管的计数器&#xff0c;我们这里介绍一款新的计数器CD4029&#xff0c;这也是很常见的计数器&#xff0c;不同的是后者可以输出BCD编码。 文章目录 一、总体效果二、CD4029的管脚和功能介绍1、芯片功能简…

【Linux】为.sh脚本制作桌面快捷方式(.desktop,可双击执行),且替换显示图标(图文详情)

目录 0.背景环境 1、原理 2、详细步骤 1&#xff09;创建.desktop快捷方式 2&#xff09; 给test.desktop快捷方式增加可执行权限 3&#xff09;编辑test.desktop内容和参数 4&#xff09;修改快捷方式属性为双击可执行 5&#xff09;将桌面快捷方式发送到桌面 0.背景环…

【TI毫米波雷达笔记】sdk type避坑

这个函数要传一个结构体进去 然后结构体里面有个adcoutcfg结构体变量 adcoutcfg结构体里面共有三个变量 一个adcbitformat结构体 另外两保留 点开adcbitformat结构体发现是个32位段 一共四级结构体 那么请问 为什么adcoutcfg变量不直接定义成一个32位无符号整形&#xff1f; 另…

RISC-V走向开放服务器规范

原文&#xff1a;RISC-V Moving Toward Open Server Specification 作者&#xff1a;Agam Shah 转载自&#xff1a;https://www.hpcwire.com/2023/07/24/risc-v-moving-toward-open-server-specification/ 中文翻译&#xff1a; 2023年7月24日 RISC-V International目前正…

nodejs实现解析chm文件列表,无需转换为PDF文件格式,在线预览chm文件以及目录,不依赖任何网页端插件

特性: 1、支持任意深度的chm文件解析 2、解析后内容结构转换为tree数据呈现 3、点击树节点可以在html实时查看数据 4、不依赖任何浏览器端插件,兼容性较好 nodejs端核心代码 const $g = global.SG.$g, fs = global.SG.fs, router = global.SG.router, xlsx = global.SG.xl…

git与github常用方法

这里写目录标题 1. Github基本使用方法2. Git使用方法3. git、VS code、Github联合使用方法4. Git配置Github远程仓库SSH密钥5 常见问题 1. Github基本使用方法 仓库&#xff08;Repository&#xff09;&#xff1a;Github上用来存放代码的空间&#xff0c;包含代码、文档和其…

Java练习

添加你喜欢的歌手以及你喜欢他唱过的歌曲&#xff0c;并遍历 package Test0726;import java.util.ArrayList; import java.util.HashMap; import java.util.*;public class SingerTest {public static void main(String[] args) {HashMap singers new HashMap();String singe…

软工导论知识框架(五)面向对象方法学

传统软件工程方法学适用于中小型软件产品开发&#xff1b; 面向对象软件工程方法学适用于大型软件产品开发。 一.四要素 对象&#xff0b;类&#xff0b;继承&#xff0b;传递消息实现通信 二.概念 1.对象&#xff1a;具有相同状态的一组操作的集合&#xff0c;对状态和操作…

批处理处理退格符,一行里输出百分比

直接上例子程序&#xff1a; echo off&setlocal enabledelayedexpansion for /l %%a in (1,1,6) do set "str!str!" rem set /p0%<nul for /L %%i in (0,1,100) do (sleep 1 >nul set /p%str%<nul&set /p%%i%%<nul ) pause>nul 输出效果如…

linuxARM裸机学习笔记(5)----定时器按键消抖和高精度延时实验

定时器按键消抖 之前的延时消抖&#xff0c;是直接借助delay函数进行的&#xff0c;但是这样会浪费CPU的性能。我们采用延时函数的方式实现&#xff0c;可以实现快进快出。 定时器消抖&#xff0c;必须是在t3的时间点才可以&#xff0c;当在t1,t2的时间点每次进入中断函数都要…

SSH 免密登录

SSH SSH&#xff08;Secure Shell&#xff09;是一种安全通道协议&#xff0c;主要用来实现字符界面的远程登录、远程复制等功能 SSH 协议对通信双方的数据传输进行了加密处理&#xff0c;其中包括用户登录时输入的用户口令 SSH 为建立在应用层和传输层基础上的安全协议。对数…

vscode关闭绑定元素“xxx”隐式具有“any”类型这类错误

在ts的项目里面&#xff0c;真的经常看到any类型的报错&#xff0c;真的很烦的 所以为了眼不见心不乱&#xff0c;我决定消除这个错误提示 在tsconfig.json里面配置 "noImplicitAny": false 就可以了 {"compilerOptions": {"target": "E…

LeetCode——只出现一次的数字II(位运算方法/哈希方法)

题目地址 力扣 题目解析 位运算法 由题我们能知道该数组中只有一个数出现了一次&#xff0c;然而其他的数都出现了3次。 我们可以通过分析每一个二进制位的和来讨论这个题目的解法&#xff01; 由于前边的条件&#xff0c;那么我们可以得出&#xff0c;某一个二进制位的和…

培训Java技术要多久才能学会?答案都在这里啦

培训Java技术要多久才能学会?这是想学习Java开发的很多人都会问到的一个问题。而这个问题的答案其实并不是那么简单&#xff0c;因为学Java的时间长短受到众多因素的影响。本文将从个人基础、学习动力和学习效率三个方面来为您解答这个问题。 1. 个人基础 自己的基础对于学习…