easy-rule规则引擎使用

简介

        轻量级的规则引擎,易于学习的api

        简单来说,规则引擎就是一个函数:y=f(x1,x2,…,xn)

        将业务代码和业务规则分离,解耦业务决策和业务代码的绑定关系

入门示例

依赖引入
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.1.0</version>
</dependency><!--规则定义文件格式,支持json,yaml等-->
<dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-support</artifactId><version>4.1.0</version>
</dependency><!--支持mvel规则语法库-->
<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>
代码示例
public static void main(String[] args) {Rules rules = new Rules();Rule rule = new RuleBuilder().name("test").description("测试").priority(3).when(facts -> facts.get("userName").equals("zhangsan")).then(facts -> System.out.println("this is test action!")).build();rules.register(rule);Facts facts = new Facts();facts.put("userName","zhangsan");DefaultRulesEngine defaultRulesEngine = new DefaultRulesEngine();defaultRulesEngine.fire(rules,facts);}
核心概念
规则(Rule)

        由条件和行动构成的推理语句,通俗的讲:当满足某个条件之后,需要做后续的动作(一个或多个动作),一般表示为IF <conditions> THEN <actions>, Rule表达逻辑。一个规则的IF部分称为LHS,THEN部分称为RHS。

除了以上示例方式构建Rule,还可以通过注解构建Rule:

@Rule(name = "repeatRule",description = "重复规则对消息内容去重",priority = 100)
public class RepeatRule {@Conditionpublic boolean evaluate(@Fact("sendMessages") Set<String> sendMessages, @Fact("message") String message) {return sendMessages.contains(message);}@Action(order =0)public void execute(Facts facts) {//}@Action(order = 1)public void breakRules(Facts facts) {facts.put("break",true);facts.put("reason","repeat limit");}}
事实(Facts)

        一组用户的输入数据,规则将根据输入数据判断是否满足条件,从而触发规则actions

        Facts是一组Fact集合,源码示例如下:

而Fact是一个容器,可以简单的理解成一个Map对象:

执行引擎(RulesEngine)

        引擎执行器,一般为推理引擎。Rules使用LHS与事实进行模式匹配。当匹配被找到,Rules会执行RHS即执行逻辑,同时actions经常会改变facts的状态,来推理出期望的结果。

        常用的执行引擎即:DefaultRulesEngine

结合mvel使用示例

@Testpublic void mvelExecute() {MVELRule repeatRule = new MVELRule().name("repeat Rule").priority(100).when("!sendMessages.contains(msgId)").then("result.put('break',true);result.put('reason','repeat limit')");Rules rules = new Rules(repeatRule);Facts facts = new Facts();facts.put("msgId","123456");facts.put("sendMessages",new TreeSet<>());facts.put("msgType","interaction");facts.put("message","hello world");facts.put("result",new HashMap<>());DefaultRulesEngine engine = new DefaultRulesEngine();//CustomRuleListener customRuleListener = new CustomRuleListener();//engine.registerRuleListener(customRuleListener);engine.fire(rules,facts);Map<String,Object> result = (Map<String,Object>)facts.get("result");log.info("执行结果是:{}", JSONUtil.toJsonStr(result));}

MVEL可以支持表达式支持常用的逻辑符:> = < && || 等,还支持java类型api的调用

最直观的使用MVEL表达是API如下:

 @Testpublic void mvelCompileTest(){MyTest obj = new MyTest();Map<String, Object> map = new HashMap<>();map.put("key1", 1);map.put("key2", 2);String expression = "func(map)";Map<String, Object> vars = new HashMap<>();vars.put("map", map);MVEL.executeExpression(MVEL.compileExpression(expression), obj, vars);System.out.println(map);}public void func(Map<String, Object> map) {map.put("test","lisi");}

详细的MVEL脚本语言的使用:http://mvel.documentnode.com/

结合spel使用示例

public static void main(String[] args) {Rules rules = new Rules();SpELRule spelRule = new SpELRule().name("1").description("1").priority(1).when("#{ ['item'].price >= 100 }").then("#{ ['item'].setExpression('折扣1折\n原价为:' + ['item'].price " +"+ '\n折扣后的价格为:'" +" + T(java.lang.Float).parseFloat(['item'].price * 0.1+'') )  }");rules.register(spelRule);Item item = new Item(500);Facts facts = new Facts();facts.put("item", item);DefaultRulesEngine defaultRulesEngine = new DefaultRulesEngine();// 触发引擎defaultRulesEngine.fire(rules, facts);System.out.println(item.getExpression());}

企业级应用

如果规则引擎的使用仅仅只如以上硬编码的使用方式,还不足以体现规则引擎的强大。试看以下代码:

@Testpublic void factoryTest() throws Exception {ClassPathResource classPathResource = new ClassPathResource("rule.yml");String absolutePath = classPathResource.getAbsolutePath();YamlRuleDefinitionReader ymlReader = new YamlRuleDefinitionReader();MVELRuleFactory mvelRuleFactory = new MVELRuleFactory(ymlReader);Rules rules = mvelRuleFactory.createRules(new FileReader(absolutePath));DefaultRulesEngine rulesEngine = new DefaultRulesEngine();JSONObject entries = new JSONObject();entries.set("productId","1");entries.set("type","1");Facts facts = new Facts();facts.put("canteen", entries);rulesEngine.fire(rules, facts);}

yml内容如下:

---
name: "规则1"
description: "prouductId = 1 && type = 1 "
condition: "canteen.productId==1&&canteen.type==1"
priority: 1
actions:- "com.byd.performance.easyruledemo.four.UserInfoService.getNowTime();"
---
name: "规则2"
description: "prouductId = 1 && type = 2"
condition: "canteen.productId == 2 && canteen.type == 1"
priority: 2
actions:- "System.out.println(2);"

以上通过配置文件定义规则,将规则的触发决策通过文本的方式表述,解耦了业务逻辑代码和规则决策,大大的提升了该引擎的实用性。试想如下业务场景:

公司为了对产品经销商加强管理,需要制定一系列的处罚措施,当触犯某条规则时,将受到相应的惩罚措施。如果采用代码实现决策过程,需要大量的if else来完成,且当需要改变处罚措施时,需要修改代码,重新发布。

如果把决策过程由以上配置文件完成(再配合规则变动刷新等措施或者直接把规则数据由数据库存储加载),可以方便的支持需求变更(此处只是讨论决策的变动,如果需要新增加某种处罚措施也需要代码调整、发布)

源码浅析

easy-rule的源码较为简单(最主要是将触发规则(Condition)和执行逻辑(Action)解耦的思想),以下以简单的示例做源码分析:

org.jeasy.rules.core.DefaultRulesEngine#doFire

可以看出执行引擎的核心逻辑逻辑清晰、简单--就是通过循环Rule,判断是否命中规则,然后执行规则逻辑即可

其中执行引擎有4个参数可设置,分别释义如下:

skipOnFirstAppliedRule:Parameter to skip next applicable rules when a rule is applied(当第一个被命中的规则执行后,是否不执行后续规则)代码line 115就是改功能的释义skipOnFirstNonTriggeredRule:Parameter to skip next applicable rules when a rule is non triggered(当有规则的判断逻辑未命中或判断是否命中异常,是否跳过后续规则,代码line102,line130 是逻辑释义)isSkipOnFirstFailedRule:Parameter to skip next applicable rules when a rule has failed(当执行某个规则逻辑异常时是否跳过后续规则)

priorityThreshold:规则优先级的阈值,超过该阈值的规则不被执行,默认值是Integer.MAX_VALUE

功能展望

在上面的企业级应用中有提到过,将规则决策由代码实现转而由配置文件(或者存储于数据库)中实现,解耦了规则和执行逻辑。(执行逻辑--知识库)知识库的更新需要走发布流程。如果实现以下功能是不是能更好的发挥该框架的功能

1  解藕知识库与业务逻辑的耦合性,维护知识库来进行知识与版本的管理

2  动态增加知识库,让JVM动态加载新的知识库

3 屏蔽语言壁垒,能够让运营、产品支持在线规则配置、发布是最终要实现的重要目标。做到无需研发接入,实时发布

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

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

相关文章

页面<html>上多了一个滚动条,定位发现是<body>里面多了一个id为trans-tooltip的div

现象分析&#xff1a; 页面根标签html多了一个滚动条&#xff0c;发现body里面多了一个id为trans-tooltip的div&#xff0c;虽然width为0&#xff0c;height为0&#xff0c;但是其子元素还是有高度&#xff0c;占据了空间&#xff0c;最终导致了滚动条&#xff1b; 根本原因&…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(十三)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 我们&#xff0c;继续讲一…

Java面试题--JVM大厂篇(1-10)

引言&#xff1a; 在这个信息时代&#xff0c;对于准备进入大厂工作的朋友们来说&#xff0c;对于JVM&#xff08;Java虚拟机&#xff09;的掌握是面试中的一项重要内容。下面是一些精选的JVM面试题&#xff0c;希望对大家能有所帮助。 正文&#xff1a; 1. JVM有哪几种垃圾收…

[CISCN2024]-PWN:gostack解析(go语言程序,syscall)

查看保护 ida比较复杂&#xff0c;建议动调配合静态分析程序运行 这里函数返回不用leave和ret&#xff0c;而是利用add rsp和ret&#xff0c;所以要动调查看到底要覆盖哪里。 完整exp&#xff1a; from pwn import* pprocess(./gostack) syscall0x4616c9 pop_rax0x40f984 po…

GB报文中的Cseq值的注意点

一、 问题现象 【问题现象】NVR使用GB接三方平台发现倍速回放时&#xff0c; 【现场拓扑】现场拓扑如下 &#xff08;1&#xff09; NVR侧使用家用宽带的方式&#xff0c;通过国标跨公网接入三方平台。 图1.1&#xff1a;网络拓扑 二、 抓包分析 INVITE sip:420000004013200…

OpenAI安全系统负责人:从头构建视频生成扩散模型

作者 | Lilian Weng OneFlow编译 翻译&#xff5c;杨婷、宛子琳、张雪聃 题图由SiliconFlow MaaS平台生成 过去几年&#xff0c;扩散模型&#xff08;Diffusion models&#xff09;在图像合成领域取得了显著成效。目前&#xff0c;研究界已开始尝试更具挑战性的任务——将该技术…

深度学习Day-18:ResNet50V2算法实战与解析

&#x1f368; 本文为&#xff1a;[&#x1f517;365天深度学习训练营] 中的学习记录博客 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制] 要求&#xff1a; 根据本文Tensorflow代码&#xff0c;编写对应的Pytorch代码了解ResNetV2与ResNetV的区别 一、 基础…

【实战JVM】-基础篇-03-Java内存结构

【实战JVM】-基础篇-03-Java内存结构 1 运行时数据区1.1 总览1.2 程序计数器1.2.1 是否会内存溢出 1.3 java虚拟机栈1.3.1 栈帧的组成1.3.1.1 局部变量表1.3.1.2 操作数栈1.3.1.3 帧数据1.3.1.3.1 动态链接1.3.1.3.2 方法出口1.3.1.3.3 异常表 1.3.2 是否会内存溢出1.3.3 设置虚…

【神经网络结构可视化】使用 Visualkeras 可视化 Keras / TensorFlow 神经网络结构

文章目录 Visualkeras介绍下载安装代码示例1、导入必要的库2、创建VGG16神经网络模型3、可视化神经网络结构4、完整代码5、使用教程 可视化自己创建的神经网络结构1、导入要的库2、创建自己的神经网络模型3、可视化神经网络结构图4、完整代码 Visualkeras介绍 Visualkeras是一…

C++代码错误解决1(函数模板)

1、代码如下 //示例函数模板的使用 #include <iostream> #include <string> using namespace std; template <typename T>//函数模板 T max(T a,T b) {return a>b?a:b; } int main() {int a,b;cout<<"input two integers to a&b:"…

【微机原理及接口技术】可编程并行接口芯片8255A

【微机原理及接口技术】可编程并行接口芯片8255A 文章目录 【微机原理及接口技术】可编程并行接口芯片8255A前言一、8255A的内部结构和引脚1.与外设接口&#xff08;数据端口&#xff09;2.与处理器接口 二、8255A的工作方式三、8255A的编程1. 写入方式控制字&#xff1a;控制字…

从0开始回顾ElasticSearch

1 elasticsearch概述 1.1 elasticsearch简介 官网: https://www.elastic.co/ ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的…

【动手学强化学习】第 6 章 Dyna-Q 算法知识点总结

【动手学强化学习】第 6 章 Dyna-Q 算法知识点总结 本章知识点基于模型的强化学习与无模型的强化学习方法简介无模型的强化学习方法基于模型的强化学习方法 强化学习算法的评价指标Dyna-Q算法Dyna-Q 算法的具体流程Dyna-Q 代码实践 本章知识点 基于模型的强化学习与无模型的强…

C++语言·list链表

其实现在在讲这些容器的时候&#xff0c;我们的重点已经不是它的接口都有什么&#xff0c;功能都是什么了&#xff0c;这些内容官网上都能查到&#xff0c;而且容器和容器之间接口的不同处很少&#xff0c;我在讲解的话也只是把官网上的东西截图下来复述一下。现在的重点其实都…

AtCoder Regular Contest 178 A~D

A.Good Permutation 2&#xff08;贪心&#xff09; 题意&#xff1a; 给你一个正整数 N N N和一个由 M M M个正整数 A ( A 1 , A 2 , … , A M ) A(A_{1},A_{2}, \dots,A_{M}) A(A1​,A2​,…,AM​)组成的序列。 在这里&#xff0c; A A A的所有元素都是介于 1 1 1和 N N …

网络编程-TCP

一、TCP的相关IP 1.1 SeverSocket 这是Socket类,对应到网卡,但是这个类只能给服务器使用. 1.2 Socket 对应到网卡,既可以给服务器使用,又可以给客户端使用. TCP是面向字节流的,传输的基本单位是字节. TCP是有连接的,和打电话一样,需要客户端拨号,服务器来听. 服务器的内核…

Stream流的使用

目录 一&#xff0c;Stream流 1.1 概述 1.2 Stream代码示例 二&#xff0c;Stream流的使用 2.1 数据准备 2.2 创建流对象 2.3 中间操作 filter map distinct sorted limit skip flatMap 2.4 终结操作 foreach count max&min collect 2.5 查找与匹配 a…

redis中String,Hash类型用法与场景使用

String 用法 1. 设置键值对 &#xff08;1&#xff09;设置键值对使用 set 命令设置 key 的值。 返回值&#xff1a;ok&#xff0c;如果 key 已经存在&#xff0c;set 命令会覆盖旧值。 &#xff08;2&#xff09;使用 setex 命令设置 key 的值并为其设置过期时间&#xff…

安全设计 | CISA:构建不可侵犯的代码,软件安全设计的未来之路

软件制造商在产品设计和开发过程中应采取安全设计原则和方法&#xff0c;以减少网络安全风险&#xff0c;并转变责任重心&#xff0c;使产品在设计时就内置安全特性&#xff0c;而不是依赖于后期的补丁和修复。为此CISA发布了《软件安全设计的原则和方法》&#xff0c;帮助软件…

兵器室管控系统|DW-306是一套成熟系统

概述 智慧兵器室管理系统&#xff08;DW-S306&#xff09;是依托互3D技术、大数据、RFID技术、数据库技术、AI、视频分析技术对RFID智能仓库进行统一管理、分析的信息化、智能化、规范化的系统。 本解决方案利用现有内部网络&#xff0c;部署部队智能兵器室管理系统&#xff…