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

目录

  • 一、序言
  • 二、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。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【密码学】密码棒密码

密码棒密码 大约在公元前700年,古希腊军队使用一种叫做scytale的圆木棍来进行保密通信。其使用方法是这样的:把长带子状羊皮纸缠绕在圆木棍上,然后在上面写字;解下羊皮纸后,上面只有杂乱无章的字符,只有再次以同样的方式缠绕到同样粗细的棍子上,才能看出所写的内容。快速且不容…

安卓源码分析(10)Lifecycle实现组件生命周期管理

参考&#xff1a; https://developer.android.google.cn/topic/libraries/architecture/lifecycle?hlzh-cn#java https://developer.android.google.cn/reference/androidx/lifecycle/Lifecycle 文章目录 1、概述2、LifeCycle类3、LifecycleOwner类4、LifecycleObserver类 1、…

聊聊51单片机

目录 1.介绍 2.发展 3.应用领域 4.发展前景 1.介绍 51单片机&#xff08;AT89C51&#xff09;是一种常见的8位微控制器&#xff0c;属于Intel MCS-51系列。它是一种低功耗、高性能的单片机&#xff0c;广泛应用于嵌入式系统中。 51单片机具有很多特点和功能&#xff0c;例如…

智慧城市美术效果Unity实现笔记流程

智慧城市美术效果Unity实现笔记流程&#xff1a; 参考 对标 效果图&#xff1a; 参考资料&#xff1a; 方案一&#xff1a; fBlender GIS 获取城市 房屋道路等数据 安装BlenderGIS插件 落叶大师智慧城市效果解析 方案二&#xff1a; CityEngine2022地块生成 写实类-参考图&…

棒球在国际上的流行·棒球1号位

棒球在国际上的流行 1. 棒球的起源与历史 棒球的起源源于美国。19世纪中叶&#xff0c;由于美国领土的扩张&#xff0c;当时的美国殖民地的印第安人将棒球类游戏&#xff0c;带到了当时的弗吉尼亚州的奥克兰。后来&#xff0c;棒球运动流传到了加利福尼亚州的圣迭戈。早期的棒…

初识鸿蒙跨平台开发框架ArkUI-X

HarmonyOS是一款面向万物互联时代的、全新的分布式操作系统。在传统的单设备系统能力基础上&#xff0c;HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念&#xff0c;能够支持手机、平板、智能穿戴、智慧屏、车机等多种终端设备&#xff0c;提供全场景&#…

adb用法,安卓的用户CA证书放到系统CA证书下

设备需root&#xff01;&#xff01;设备需root&#xff01;&#xff01;设备需root&#xff01;&#xff01; ​​​​​​​测试环境&#xff1a;redmi 5 plus、miui10 9.9.2dev&#xff08;安卓8.1&#xff09;、已root win下安装手机USB驱动&#xff08;过程略&#xff0c…

OPENCV C++(十二)模板匹配

正常模板匹配函数 matchTemplate(img, templatee, resultMat, 0);//模板匹配 这里0代表的是方法&#xff0c;一般默认为0就ok img是输入图像 templatee是模板 resultmat是输出 1、cv::TM_SQDIFF&#xff1a;该方法使用平方差进行匹配&#xff0c;因此最佳的匹配结果在结果为…

R语言5_安装Giotto

环境Ubuntu22/20, R4.1. 已开启科学上网。 第一步&#xff0c;更新服务器环境&#xff0c;进入终端&#xff0c;键入如下命令&#xff0c; apt-get update apt install libcurl4-openssl-dev libssl-dev libxml2-dev libcairo2-dev libgtk-3-dev libhdf5-dev libmagick9-dev …

[HDLBits] Exams/2012 q1g

Consider the function f shown in the Karnaugh map below. Implement this function. (The original exam question asked for simplified SOP and POS forms of the function.) //

第三章 图论 No.9有向图的强连通与半连通分量

文章目录 定义Tarjan求SCC1174. 受欢迎的牛367. 学校网络1175. 最大半连通子图368. 银河 定义 连通分量是无向图的概念&#xff0c;yxc说错了&#xff0c;不要被误导 强连通分量&#xff1a;在一个有向图中&#xff0c;对于分量中的任意两点u&#xff0c;v&#xff0c;一定能从…

Easys Excel的表格导入(读)导出(写)-----java

一,EasyExcel官网: 可以学习一些新知识: EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 二,为什么要使用easyexcle excel的一些优点和缺点 java解析excel的框架有很多 &#xff1a; poi jxl,存在问题&#xff1a;非常的消耗内存&#xff0c; easyexcel 我们…

arcgis栅格数据之最佳路径分析

1、打开arcmap&#xff0c;加载数据&#xff0c;需要对影像进行监督分类&#xff0c;如下&#xff1a; 这里任选一种监督分类的方法&#xff08;最大似然法&#xff09;&#xff0c;如下&#xff1a; 这里会先生成一个.ecd文件&#xff0c;然后再利用.ecd文件对影像进行分类。如…

新知识:Monkey 改进版之 App Crawler

原生Monkey 大家知道Monkey是Android平台上进行压力稳定性测试的工具&#xff0c;通过Monkey可以模拟用户触摸屏幕、滑动、按键等伪随机用户事件来对设备上的程序进行压力测试。而原生的Android Monkey存在一些缺陷&#xff1a; 事件太过于随机&#xff0c;测试有效性大打折扣…

软件设计师(七)面向对象技术

面向对象&#xff1a; Object-Oriented&#xff0c; 是一种以客观世界中的对象为中心的开发方法。 面向对象方法有Booch方法、Coad方法和OMT方法等。推出了同一建模语言UML。 面向对象方法包括面向对象分析、面向对象设计和面向对象实现。 一、面向对象基础 1、面向对象的基本…

207、仿真-51单片机脉搏心率与血氧报警Proteus仿真设计(程序+Proteus仿真+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选择 方案一&a…

Java SpringBoot 加载 yml 配置文件中字典项

实际项目中&#xff0c;如果将该类信息放配置文件中的话&#xff0c;一般会结合Nocas一起使用 将字典数据&#xff0c;配置在 yml 文件中&#xff0c;通过加载yml将数据加载到 Map中 Spring Boot 中 yml 配置、引用其它 yml 中的配置。# 在配置文件目录&#xff08;如&#xff…

Mask RCNN网络结构以及整体流程的详细解读

文章目录 1、概述2、Backbone3、RPN网络3.1、anchor的生成3.2、anchor的标注/分配3.3、分类预测和bbox回归3.4、NMS生成最终的anchor 4、ROI Head4.1、ROI Align4.2、cls head和bbox head4.3、mask head 1、概述 Mask RCNN是在Faster RCNN的基础上增加了mask head用于实例分割…

Games101学习笔记 - MVP矩阵

MV矩阵&#xff08;模型视图变换&#xff09; 目的&#xff0c;把摄像机通过变换移动的世界坐标远点&#xff0c;并且朝向与Z轴的负方向相同。这个变换就是模型试图变换。 因为移动了相机&#xff0c;如果想保持正确的渲染的话&#xff0c;那么对应的物体需要要和相机保持相对…