分享好友 最新动态首页 最新动态分类 切换频道
Easy Rules规则引擎实战
2024-12-26 23:57

Easy Rules规则引擎实战

1、是什么

  • 基于java轻量级的规则引擎,学习成本更低、适用性更强
  • 本质一个函数,y=f(x1,x2,…,xn)
  • Easy Rules 每条规则都有一个条件(condition)和一个动作(action,简单地说,可以将其看作是一组 IF THEN 或类似SQL的when-then语句

2、作用

  • 解决业务代码和业务规则分离,实现了将业务决策从应用程序代码中分离。 接受数据输入,解释业务规则,并根据业务规则做出业务决策。

业务系统在应用过程中,常常包含着要处理"复杂、多变"的部分,这部分往往是"业务规则"或者是"数据的处理逻辑"。因此这部分的动态规则的问题,往往需要可配置,并对系统性能和热部署有一定的要求。从开发与业务的视角主要突出以下的一些问题

  • 从开发人员视角来看

1)逻辑复杂,要使用大量if-else来实现,或者使用设计模式。但过于复杂的规则逻辑,使用设计模式也往往是存在大量并且关系复杂的类,导致代码难于维护,对新加入的同学极不友好。

2)变更时需要从头梳理逻辑,在适当的地方进行if…else…代码逻辑调整,耗费大量时间进行梳理。

3)开发周期较长,当需求发生变更时,需要研发人员安排开发周期上线,对于当下快速变化的业务,传统的开发工作方式显得捉襟见肘。

  • 从业务人员视角来看

1)业务人员期望友好的管理界面,不需要专业的开发技能就能够完成规则的管理、发布。

2)期望能够实现热部署,由业务人员配置好之后即配即用。

3)减少业务规则对开发人员的依赖。

4)降低需求变动的时间成本,快速验证发布

3、怎么做

你可以自己构建一个简单的规则引擎。你所需要做的就是创建一组带有条件和动作的规则对象rule,将它们存储在一个集合中rules,然后遍历它们以评估(fire)条件(condition)并执行这些动作(action)。

pom

 
 

大多数业务规则可以由以下定义表示

  • 名称name:规则命名空间中的唯一规则名称

  • 说明description:规则的简要说明

  • 优先级priority:相对于其他规则的规则优先级,较小的值表示较高的优先级

  • 事实fact:去匹配规则时的一组已知事实

  • 条件condition:为了匹配该规则,在给定某些事实的情况下应满足的一组条件

    如果规则条件为true,则规则将被触发执行。否则,规则将被忽略

  • 动作action:当条件满足时要执行的一组动作(可以添加/删除/修改事实

    它可以用于实现各种应用程序逻辑,例如更新数据、发送消息等。

抽象规则Rule

 

基础规则BasicRule

 
事实类Facts:map
 
  • 扩展:可以将普通对象(包含属性|方法)facts.put()。也可以将rpc对象put进来
 
条件接口
 
动作接口
 

四种规则定义方式

注解方式

1、eg1(也可以实现Rule接口

 

2、纯注解

 
RuleBuilder 链式

1、eg1

 

2、eg2

 
Mvel和Spel表达式

1、eg1:Mvel表达式

Mvel表达式

 
  • when:对象属性

when方法参数,只能是facts对象中key对象,内部定义的属性或方法

 

2、补充

  • when、then内容,可以从自定义的json文件中读取并解析成Mvel表达式形式。解析过程可参考场景6

3、eg2:Spel表达式同理

Spel表达式

Yml配置

eg1: weather-rule.yml

 
  • condition:对象方法
 

eg2:一个yml文件创建多个规则

 
  • 读取多条规则
 

常用规则类

DefaultRule
 
SpELRule(Spring的表达式注入

表达式注入

 
  • when方法-SpELCondition
 
  • then方法- SpELAction
 

组合规则

抽象CompositeRule类由一组规则组成。这是一个典型地组合设计模式的实现。可以以不同方式触发组合规则。

三种CompositeRule具体子类

UnitRuleGroup : 要么应用所有规则,要么不应用任何规则(AND逻辑
ActivationRuleGroup : 它触发第一个适用规则,并忽略组中的其他规则(XOR逻辑
ConditionalRuleGroup : 如果具有最高优先级的规则计算结果为true,则触发其余规则

UnitRuleGroup
  • 规则1
 
  • 规则2
 
  • 执行
 
  • 输出
 

先输出规则2(优先级为777,规则1(优先级为默认值:2147483646,值越小,优先级越高

引擎接口

 

引擎抽象类

AbstractRuleEngine作用就是抽出多个引擎类共有的,不需要再各自额外重复去实现

引擎类-DefaultRulesEngine

 
规则引擎参数(决定规则之间是否互斥|中断|跳过等)

RulesEngineParameters

 
 

场景1- 恒打印

规则description

默认打印Hello World

规则
 
规则引擎:使用DefaultRulesEngine
执行
 

输出

 
fire方法执行流程
 

场景2-yml

1、规则description

if it rains then take an umbrella

2、定义规则

weather-rule.yml

 

3、自定义规则引擎:使用默认的

4、执行

 

场景3 简单if-else

1、功能描述

从1数到100,并且:

  • 需求1:如果数字是5的倍数,则打印"i :是5的倍数"
  • 需求2:如果数字是7的倍数,请打印"i :是7的倍数"
  • 需求3:如果数字是5和7的倍数,请打印"i :是5的倍数、7的倍数"
  • 需求4:否则打印数字本身

2、常规实现方法

 

3、使用Easy Rules规则引擎实现

将每个需求编写一条规则:

  • rule1
 
  • rule2
 
  • rule3
 
  • rule4
 
  • 执行
 
  • 这里规则引擎参数:skipOnFirstAppliedRule(true):告诉引擎,被触发时跳过后面的规则。

    即当i = 5时,满足规则1(mod5,执行完action1,就不会再去匹配其他rule2、3、4规则了。使用场景是:各个规则之间互斥

场景4-动态规则MVEL表达式+Json字符串

如图1

输入facts:NORMAL_NUMBER和ERROR_NUMBER两个值,使用Mvel表达式解析facts是否满足上述json中定义的condition

  • 操作符枚举类(加减乘除,> 、<)
 
  • 逻辑运算符(&&、||、and、or
 
  • 工具类(负责解析自定义json字符串中的condition和action内容,赋值给Mvel规则when、then
 
  • 测试
 

结果分析:显然结果匹配成功。原因如图2

facts:NORMAL_NUMBER = 10、ERROR_NUMBER = 10

condition:如图1

显然NORMAL_NUMBER = 10,满足第一个条件 < 11,直接返回true。

如果我们设置fact:NORMAL_NUMBER = 12,则NORMAL_NUMBER 不满足第一个条件。

但是fact中ERROR_NUMBER = 10 <= 11满足第二个条件,直接返回True

场景5-QLExpress

1、使用阿里的QLExpress

 
 
  • MetaRuleResult
 

2、使用EasyRules实现上述功能

  • 规则1
 

这里的规则是原子规则

  • 规则2
 
  • 自定义组合规则
 

作用:这里的规则是组合规则,是原子规则的组合形式,可扩展

这里的自定义规则组合,是快速失败机制:即l&&o中如果lRule的condiotion为false,则直接失败,使用facts记录一个失败原因。也可以自定义将每个rule-condition为false的原因都记录下来

  • 自定义condition-after-listeren
 

作用:组合规则,执行结果。成功|失败,已经失败原因

  • 执行
 
  • 扩展

1)db获取规则表达式

先根据网店+品类+角色+修改类型,查询db获取组合规则,比如l&&o

2)工厂模式解析组合规则

然后根据l&&o,解析出规则为l和o,组合成l&&o

3)facts获取数据

自定义策略模式,key为枚举类型,value为对应的rpc查询接口

 

这里的queryData方法,根据规则类型o,获取对应的Rpc接口-ORGateway,然后查询or值,然后比较结果

4)组合规则中,判断每个原子规则是否执行通过,失败则记录对应执行失败原因

5)在condition-after中自定义listeren,如果组合规则condition为false,则记录组合规则整体的执行失败以及失败原因

6)如果组合规则整体执行失败,则本次结果为false

场景6- 动态规则Mvel + Json文件

1、背景

动态规则就是由于业务场景的变化,之前的规则已经不适用现在的业务场景,需要更改相对应的规则。

例如:之前是满300减30,现在是满200-30

  • 正常情况下我们需要改规则类里面的比较参数代码,然后打包上线。
  • 如果使用动态规则,修改一下配置中的规则json文件即可,线上代码会读取最新的规则配置文件,无需上线

2、前提说明

1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数

2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则

 

3、场景

  • 输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实

    • 方式一:condition中制定(推荐,可以动态配置0和11
    • @Condition修饰方法入参( @Fact(“person”) Person person )
     
      
    • 方式二:将condition条件判断,自定在fact-key中对象的属性和方法中(不推荐
 
 
  • 如果学历等级符合规则,则去查询学历证书情况(集合存储)

  • 查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为

    • 学历证书数量与学历等级相同
    • 最大学历证书的学历等级与学历等级一致
  • 匹配通过则学历真实,信息中会添加真实学历匹配结果

  • 未匹配通过则学历造假嫌疑,信息中会添加造假学历信息

上线

2、前提说明

1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数

2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则

 

3、场景

  • 输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实

    • 方式一:condition中制定(推荐,可以动态配置0和11
    • @Condition修饰方法入参( @Fact(“person”) Person person )
     
      
    • 方式二:将condition条件判断,自定在fact-key中对象的属性和方法中(不推荐
 
 
  • 如果学历等级符合规则,则去查询学历证书情况(集合存储)

  • 查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为

    • 学历证书数量与学历等级相同
    • 最大学历证书的学历等级与学历等级一致
  • 匹配通过则学历真实,信息中会添加真实学历匹配结果

  • 未匹配通过则学历造假嫌疑,信息中会添加造假学历信息

场景7-履约缺货处罚金额计算

1、背景

如果商家发生了履约缺货,则需要对商家进行罚款,罚款金额计算的逻辑如下

这里以skuId=1,skuName=“苹果”, 供应商id=777为例

  • 假设供应商777,履约缺货了3件,即less = 3 pcs
  • 此sku的销售Gmv即saleGmv = 100元
  • 此sku的销售件数即saleCount = 5 pcs

则需要对777这个商家,关于skuId=1的品进行罚款,罚款金额Java代码实现如下

 
  • 缺点1

这里商家skuId=1缺货了3件,按照这个逻辑Java代码实现没有问题,加入skuid=1缺货了300件,则不能按照这个罚款的计算逻辑,计算逻辑就要重新Java代码实现,或者大量的if-else。这里仅有6中分支,加入分支很多很多,则代码变得异常臃肿。

  • 缺点2

假如代码实现后,那天业务变更了计算公式的一个值,或者干脆改变了计算逻辑max->min,则只能通过代码上线。

  • 使用when-then形式解决大量分支问题,而且支持动态加载,无需上线代码

实现如下

2、实现

 

3.监听器

通过监听器,如果then执行成功了,则一定会执行监听器的onSuccess方法。故在此再执行一遍then表达式,获取then的执行结果存入map中(这里之所以要通过监听器来存then的结果,原因是原生的MvelRule规则的execute方法返回值类型是void,它只关系then中的表达式是否执行成功,不关系表达式执行的结果

 

补充

1.调用类的带参数方法

 

2.调用类不带参方法

 

场景8:Mvel表达式when-then调用类方法

1、背景

当满足when(指定类的方法,则执行then(执行类的方法

2、举例

  • 定义类的when-then方法
 
  • 执行
 

场景9:终极模式之规则引擎+职责链

我mjp愿称之为EasyRules最强实战场景2024.01.07

1、背景

综合上述场景7和8。

我们知道规则的处罚动作actions可能不止一个。除了对商家进行罚款,还可以对商家停排期,甚至可以降低商家商品的曝光度等等一系列处罚动作。

基于此,我们可以将处罚actions配置为json字符串

 

2、特殊化

规则1

  • when是 0<less<=10
  • actions是
 

规则2

  • when是 0<less<=10
  • actions是
 

即规则2的处罚动作只有罚款

那么问题来了,如何为每个规则,定制化处罚actions动作

答案:通过职责链模式

3、思想

  • 我们代码中使用职责链模式,定义一系列的Handler处理器。

然后每一条规则的actions =》映射成List handlerList,然后遍历执行处理器。

  • 因为不同的规则,处罚动作actions可能不一样,所以,其处理器handlerList也不尽相同,需要自己定制化

4、代码实现

  • 业务代码执行
 
  • 方法类Demo
 
  • 处理器接口
 
  • 处理器实现类

    罚款处理器

 

​ 停排处理器

 
  • 根据入参定制化处理器集合

    处理器接口默认都不参与,根据json的key添加谁参与

     
 

5、罚款处理器扩展

罚款处理器中,也可以使用Mvel表达式,直接计算罚款多少钱

 
补充:MVEL直接调用类方法

1.调用类的带参数方法

 

2.调用类不带参方法


最新文章
微信外链新闻:全面外链策略指南
网站外链建设规划目标:建立高质量的外链网络,提高网站在搜索引擎结果页面 (SERP) 中的排名和可见度。策略:* 创建有价值的内容:撰写信息丰富、引人入胜且相关的文章、博客文章和指南,为受众提供价值。* 接触相关网站和影响者:寻找相关
真人投票点赞拉票群,微信投票代投
真人投票拉票群,微信投票代投真人投票拉票群微信投票代投是一种便捷的投票服务,专为各类比赛活动设计。本群提供真人拉票服务,确保每一票都是真实有效的,以支持您的选手获得更多关注与荣誉。我们还提供代投服务,无论您的选手身处何地,
探索“天空之城”新纪元——城市低空起降设施体系规划的若干思考
点击蓝字关注我们上海市土木工程学会作为自然资源领域专业咨询服务商,城建设计集团一直在思考如何率先在空地一体化领域开展规划探索与创新转型,先行成立城市立体交通研发中心(低空交通中心),聚焦低空经济发展的规划设计和技术应用,努
流畅的win10电脑系统 最流畅win10系统
1、win10装哪个版本最好2、最流畅的win10有哪些3、win10最稳定流畅的版本4、win10系统需要什么配置才能流畅的玩5、win10哪个系统打游戏更流畅1、win10哪个版本最稳定兼容性最好:总体来说,win10专业版是兼容性较好的。win10不同版本之间的
如何通过百度SEO优化提升网站排名增加潜在客户流量
随着互联网技术的不断发展,越来越多的人开始关注网络营销这一领域。无论是个人创业者,还是大型企业,都意识到通过互联网平台推广产品、品牌的重要性。特别是在百度等搜索引擎优化(SEO)方面,如何有效提升自己的网站排名,吸引更多的潜
翼真L380提升幸福感 智能配置和质感都不输大牌
刚步入社会时,收入一般不会太可观,此时一辆经济高性价比的车型往往是最合适的。在与同级别车型的竞争中,在空间表现上值得一说。接下来就和小编一起看看吧。先来看下翼真L380的外观,翼真L380前脸提升了整车的档次,让人过目不忘。头灯非
阴阳师百闻牌输出式神卡牌评分 最强输出单卡排名攻略
在阴阳师百闻牌里,输出类式神是现在最为主流的式神,但它们的单卡的质量并不统一,究竟哪些单卡强度高,应该是我们合卡和抽卡的目标呢?下面就为大家带来详细的攻略介绍,一起来看看吧! 更多攻略点击:阴阳师百闻牌式神大全 这是一篇基于
惠州seo工作室(惠州seo公司)
大家好,今天小编关注到一个比较有意思的话题,就是关于惠州seo工作室的问题,于是小编就整理了1个相关介绍惠州seo工作室的解答,让我们一起看看吧。专业网站建设如何给企业带来最大回报?随着早期互联网的兴起,网站是一个公司的标配,可
第十一章 文件操作_C语言插入、删除、更改文件内容
我们平时所见的文件,例如 txt、doc、mp4 等,文件内容是按照从头到尾的顺序依次存储在磁盘上的,就像排起一条长长的队伍,称为顺序文件。 除了顺序文件,还有索引文件、散列文件等,一般用于特殊领域
相关文章
推荐文章
发表评论
0评