EasyRules

规则引擎使用简介(easyRules)

github地址:https://github.com/j-easy/easy-rules

参考文章:https://www.jianshu.com/p/9b67ab434795
https://my.oschina.net/crosschen/blog/4803180
http://t.zoukankan.com/rongfengliang-p-12693489.html

为什么要用规则引擎替代if-else?

世界上最遥远的距离,是我在if里你在else里

为什么会使用到if-else?

  • 刚开始自己写的代码很简洁,逻辑清晰,函数精简,没有一个if-else
    但是需求发展却不以人的意志为转移
  • 业务逻辑千奇百怪
  • 需求无限叠加
  • 项目进度约束

由于以上诸多原因,最终代码中会出现很多的if-else,而且更有甚者有很多嵌套的if-else,着会给接锅者头越来越秃

使用if-else的场景主要有

  • 异常逻辑处理
  • 特殊case处理
  • 不同状态处理

过多的繁琐的if-else不但会降低程序的性能,还不利于后期维护,有可能出现昨天写的代码,今天来看“我靠!这是啥呀!!”

现在有一个相对较好的工具可以帮助我们进行复杂逻辑处理,那就是规则引擎。

什么是规则引擎

如果是简单的逻辑判断可以通过if-else轻松解决,但是,现实中的业务逻辑不允许我们轻松解决,一旦业务逻辑复杂了,if-else接那么香了,规则引擎就不同,你可以根据业务场景来编写不同的规则,即使业务变更了,只需要修改或添加相关的规则就可,然后引用不同的规则进行逻辑处理,这样做可以极大的降低开发成本和运维的难度,也变相保护了大伙的头发,何乐而不为呢?!

规则引擎应用场景

  • 流程分支非常复杂,规则变量庞大,常规编码(if-else)难以实现
  • 有不确定性的需求,变更频率较高
  • 需要快速做出响应和决策
  • 规则变更期望脱离于开发人员,脱离coding

规则引擎流程

在这里插入图片描述

业务规则发展历程

在这里插入图片描述

相关工具

Drools, easy-rules,Rule Book(未了解过)

Droolseasy-rulesRule Book
简介可以执行复杂事件处理的规则引擎简单轻量级的规则引擎支持Lambda的轻量级规则引擎
流行度8.7 ★★★★★8.0 ★★★★5.1 ★★★
活跃度9.4 ❤❤❤❤❤7.5 ❤❤❤❤4.4 ❤❤❤
代码质量L1(Lumnify统计L5(Lumnify统计
当前版本7.47.0.FinalV 4.1V 0.12
版本支持7.x 版本已持续多年仅支持 4.1.x,老版本不支持更新2018年5月发布V 0.11,V 0.12发布时间不详
编程语言JavaJavaJava
算法RETE算法--

在这里插入图片描述

easy-rules使用简介

相关依赖:

<dependencies>
        <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>

        <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-mvel</artifactId>
            <version>4.1.0</version>
        </dependency>
</dependencies>
规则定义
  1. 基于注解的javaBean定义

    使用@Rule来定义一个规则,@Condition 申明规则条件判断(只能有一个),@Action 申明规则执行内容(可有多个,并且可以通过order指定优先级)

    @Rule(name = "weather rule", description = "if it rains then take an umbrella")
    class WeatherRule {
    
        @Condition
        public boolean itRains(@Fact("rain") boolean rain) {
            return rain;
        }
        
        @Action(order = 0)
        public void takeAnUmbrella() {
            System.out.println("It rains, take an umbrella!");
        }
        
        @Action(order = 1)
        public void takeAnUmbrella() {
            System.out.println("It rains, take an umbrella2!");
        }
    }
    

    测试样例:

        public static void main(String[] args) {
            Facts facts = new Facts();
            facts.put("rain", true);
    
            // define rules
            Rules rules = new Rules();
            rules.register(new WeatherRules());
    
            // fire rules on known facts
            RulesEngine rulesEngine = new DefaultRulesEngine();
            rulesEngine.fire(rules, facts);
        }
    
  2. 流式编程方式实现

    通过RuleBuilder来定义一个规则,并在规则上直接定义规则内容

    Rule weatherRule = new RuleBuilder()
            .name("weather rule")
            .description("if it rains then take an umbrella")
            .when(facts -> facts.get("rain").equals(true))
            .then(facts -> System.out.println("It rains, take an umbrella!"))
            .build();
    

    测试代码:

    public class FluentTest {
    
        public static void main(String[] args) {
            Rule weatherRule = new MVELRule()
                    .name("weather rule")
                    .description("if it rains then take an umbrella")
                    .when("rain == true")
                    .then("System.out.println(\"It rains, take an umbrella! \nThat's fluentTest!\");");
    
            Rules rules = new Rules();
            rules.register(weatherRule);
    
            Facts facts = new Facts();
            facts.put("rain", true);
    
            RulesEngine engine = new DefaultRulesEngine();
            engine.fire(rules, facts);
        }
    }
    
  3. 表达式定义

    通过MVELRule类来定义一个规则,通过表达是的方式在规则类上定义规则内容

    Rule weatherRule = new MVELRule()
            .name("weather rule")
            .description("if it rains then take an umbrella")
            .when("rain == true")
            .then("System.out.println(\"It rains, take an umbrella!\");");
    

    测试代码:

    public class ExpressionTest {
    
        public static void main(String[] args) {
            Rule weatherRule = new MVELRule()
                    .name("weather rule")
                    .description("if it rains then take an umbrella")
                    .when("rain == true")
                    .then("System.out.println(\"It rains, take an umbrella! \nThat's ExpressionTest\");");
    
            Rules rules = new Rules();
            rules.register(weatherRule);
    
            Facts facts = new Facts();
            facts.put("rain", true);
    
            RulesEngine engine = new DefaultRulesEngine();
            engine.fire(rules, facts);
        }
    }
    
  4. yml文件定义

    通过定义一个yml规则文件,在通过读取文件来获取规则

    通过MVELRuleFactory类来获取yml文件定义的规则

    需要添加依赖

    <dependency>
        <groupId>org.jeasy</groupId>
        <artifactId>easy-rules-mvel</artifactId>
        <version>4.1.0</version>
    </dependency>
    

    yml文件:

    文件路径:resource/rules/rain.yml

    在这里插入图片描述

    name: "weather rule"
    description: "if it rains then take an umbrella"
    condition: "rain == true"
    actions:
      - "System.out.println(\"It rains, take an umbrella!\");"
    

    文件读取:

    MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
    Rule weatherRule = ruleFactory.createRule(new FileReader("rain.yml"));
    

    测试代码:

    public class YmlTest {
    
        public static void main(String[] args) {
            MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
            
            // 读取规则文件
            String path = YmlTest.class.getResource("/rules/rain.yml").getPath();
    
            try {
                FileReader ymlReader = new FileReader(path);
                Rule rule = ruleFactory.createRule(ymlReader);
    
                Rules rules = new Rules();
                rules.register(rule);
    
                Facts facts = new Facts();
                facts.put("rain", true);
    
                RulesEngine engine = new DefaultRulesEngine();
                engine.fire(rules, facts);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
  5. json文件定义

    通过定义一个json规则文件,在通过读取文件来获取规则

    通过MVELRuleFactory类来获取json文件定义的规则

    需要添加依赖(若需要用到UnitRuleGroup相关类则需要添加第二个依赖)

    <dependency>
        <groupId>org.jeasy</groupId>
        <artifactId>easy-rules-mvel</artifactId>
        <version>4.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.jeasy</groupId>
        <artifactId>easy-rules-support</artifactId>
        <version>4.1.0</version>
    </dependency>
    

    json文件:

    //单个规则
    [
        {
            "name": "3",
            "description": "if it rains then take an umbrella",
            "condition": "rain == true",
            "priority": 3,
            "actions": [
              "System.out.println(\"It rains, take an umbrella!\")"
            ]
    	}
    ]
    // 多个规则
    [
      {
        "name": "1",
        "description": "1",
        "priority": 1,
        "compositeRuleType": "UnitRuleGroup",
        "composingRules": [
          {
            "name": "2",
            "description": "2",
            "condition": "user.getAge()<28",
            "priority": 2,
            "actions": [
              "System.out.println(\"UnitRuleGroup not ok rule2\")"
            ]
          },
          {
            "name": "3",
            "description": "3",
            "condition": "user.name.length<10",
            "priority": 3,
            "actions": [
              "System.out.println(\"UnitRuleGroup rule3\")"
            ]
          },
          {
            "name": "4",
            "description": "4",
            "condition": "user.name.length<10",
            "priority": 4,
            "actions": [
              "System.out.println(\"UnitRuleGrouprule4\")"
            ]
          },
          {
            "name": "5",
            "description": "5",
            "condition": "user.name.length<10",
            "priority": 5,
            "actions": [
              "System.out.println(\"UnitRuleGrouprule5\"), UserService.doAction4(user.userinfo)"
            ]
          }
        ]
      },
      {
        "name": "3",
        "description": "3",
        "condition": "user.name.length<50",
        "priority": 3,
        "actions": [
          "System.out.println(\"defaultrule3\")"
        ]
      }
    ]
    

    文件读取:

    MVELRuleFactory jsonFactory = new MVELRuleFactory(new JsonRuleDefinitionReader());
    Rule weatherRule = ruleFactory.createRule(new FileReader("weather-rule.json"));
    

    测试代码:

    public static void main(String[] args) {
            MVELRuleFactory factory = new MVELRuleFactory(new JsonRuleDefinitionReader());
    
            // 读取json文件
            String path = JsonTest.class.getResource("/rules/rain.json").getPath();
    
            try {
                FileReader jsonFile = new FileReader(path);
                Rule rule = factory.createRule(jsonFile);
    
                Rules rules = new Rules();
                rules.register(rule);
    
                Facts facts = new Facts();
                facts.put("rain", true);
    
                RulesEngine engine = new DefaultRulesEngine();
                engine.fire(rules, facts);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    读取json文件时报了个错,我理解因该是要将json对象构造为数据结构,就算是单个规则也要已数据结构存放才行,我把json文件中的内容使用‘[ ]’ 框起来就好了。

    在这里插入图片描述

执行规则大致流程:

public class Test {
    public static void main(String[] args) {
        // define facts
        Facts facts = new Facts();
        facts.put("rain", true);

        // define rules 构造rule的形式有上面列举的几种
        Rule weatherRule = ...
        Rules rules = new Rules();
        rules.register(weatherRule);

        // fire rules on known facts
        RulesEngine rulesEngine = new DefaultRulesEngine();
        rulesEngine.fire(rules, facts);
    }
}
执行引擎(engine)

easyRules提供了两种引擎,分别是DefaultRulesEngine和InferenceRulesEngine

DefaultRulesEngine:根据设置的priority 来执行规则,若不设置priority则根据默认的顺序执行,每个规则只执行一次

InferenceRulesEngine:循环执行规则,只有当所有规则无法匹配成功才结束匹配(这里会出现死循环)

在对InferenceRulesEngine做测试时,我想每次在Condition中修改Face对象,但是并没有找到操作的方法,想了一下,condition中仅仅只是做判断的,好像不具备逻辑处理的能力,我觉得这是合理的,如果condition中做逻辑处理就违背了它的本职,最多也只能调用外部方法进行逻辑判断,而不是直接进行逻辑处理,逻辑处理应该要交到Action中进行。

引擎参数

参数类型是否必填默认值描述
rulePriorityThresholdintnoMaxInt当规则的priority超过设置的阈值,跳过规则
skipOnFirstAppliedRulebooleannofalse当第一个规则执行成功时,跳过下一个规则
skipOnFirstFailedRulebooleannofalse当第一个规则执行失败时,跳过下一个规则
skipOnFirstNonTriggeredRulebooleannofalse当第一个规则未触发时,跳过下一个规则

测试:

  • skipOnFirstAppliedRule参数

    @Rule(name = "fiveRules", description = "this is fiveRules")
    public class FiveRules {
    
        @Condition
        public boolean isFive(@Fact("number") Integer number){
           return number % 5 == 0;
        }
    
        @Action
        public void isFizz(@Fact("number") Integer number){
            System.out.println(number + "是5的倍数");
        }
    
        @Priority
        public int getPriority(){
            return 5;
        }
    }
    
    @Rule(name = "sevenRules", description = "this is sevenRules")
    public class SevenRules {
    
        @Condition
        public boolean isSeven(@Fact("number") Integer number){
            return number % 7 == 0;
        }
    
        @Action
        public void then(@Fact("number") Integer number){
            System.out.println(number + "7的倍数!");
        }
    
        @Priority
        public int getPriority(){
            return 10;
        }
    }
    
    		Rules rules = new Rules();
            rules.register(new SevenRules());
            rules.register(new FiveRules());
    //        rules.register(new FiveOrSevenRules(new FiveRules(), new SevenRules()));
    //        rules.register(new NonFiveOrSevenRules());
    
            Facts facts = new Facts();
    
            facts.put("number", 35);
    
            RulesEngineParameters parameters = new RulesEngineParameters();
            parameters.setSkipOnFirstAppliedRule(true);
    
            RulesEngine engine = new DefaultRulesEngine(parameters);// 应用参数
            RulesEngine engine1 = new DefaultRulesEngine();// 不应用参数
            
            engine.fire(rules, facts);
            System.out.println("--------------------------");
            engine1.fire(rules, facts);
            System.out.println("--------------------------");
    
    运行结果:
    35
    35是5的倍数
    --------------------------
    35
    35是5的倍数
    357的倍数!
    --------------------------
    
  • skipOnFirstFailedRule参数

    这个参数有点没整明白,失败跳过下一个规则,我理解的应该是返回false则不会执行下一个规则,但是即便第一个规则返回了false,下一个规则还是被执行了;也尝试了抛异常然后就不执行下一个规则,但是就算抛了异常,下一个规则还是被执行了,所以我有点不太懂了,代码就不贴了

  • skipOnFirstNonTriggeredRule参数
    这个和上面那个一样,没整明白!!!!

  • rulePriorityThreshold参数
    只有priority参数小于等于设置的值时规则才会被触发

    @Rule(name = "fiveRules", description = "this is fiveRules")
    public class FiveRules {
    
        @Condition
        public boolean isFive(@Fact("number") Integer number){
        	System.out.println("触发规则isFive");
    		return number % 5 == 0;
        }
    
        @Action
        public void isFizz(@Fact("number") Integer number){
            System.out.println(number + "是5的倍数");
        }
    
        @Priority
        public int getPriority(){
            return 5;
        }
    }
    
    @Rule(name = "sevenRules", description = "this is sevenRules")
    public class SevenRules {
    
        @Condition
        public boolean isSeven(@Fact("number") Integer number){
            System.out.println("触发规则isSeven");
            return number % 7 == 0;
        }
    
        @Action
        public void then(@Fact("number") Integer number){
            System.out.println(number + "7的倍数!");
        }
    
        @Priority
        public int getPriority(){
            return 10;
        }
    
    }
    
    public static void main(String[] args) {
          RulesEngine engine = new DefaultRulesEngine(parameters);
    
            Rules rules = new Rules();
            rules.register(new SevenRules());
            rules.register(new FiveRules());
    
            Facts facts = new Facts();
    
            facts.put("number", 7);
    
            RulesEngineParameters parameters = new RulesEngineParameters();
    //        parameters.setSkipOnFirstAppliedRule(true);
    //        parameters.setSkipOnFirstFailedRule(true);
    //        parameters.setSkipOnFirstNonTriggeredRule(true);
            parameters.setPriorityThreshold(5);
    
            RulesEngine engine = new DefaultRulesEngine(parameters);
            RulesEngine engine1 = new DefaultRulesEngine();
            
            engine.fire(rules, facts);
            System.out.println("--------------------------");
            engine1.fire(rules, facts);
            System.out.println("--------------------------");
        }
    
    运行结果:
    触发规则isFive
    --------------------------
    触发规则isFive
    触发规则isSeven
    77的倍数!
    --------------------------
    
规则监听
触发方法名触发时机
beforeEvaluate在执行规则Condition之前执行
afterEvaluate在执行完规则Condition之后执行
onEvaluationError在执行规则Condition中发生异常后执行
beforeExecute在执行规则Action之前执行
onSuccess在执行规则Action完成后执行
onFailure在执行规则Action发生异常之后执行

监听类:

public class MyRules implements RuleListener {
    @Override
    public boolean beforeEvaluate(Rule rule, Facts facts) {
        System.out.println("beforeEvaluate 触发");
        return true;
    }

    @Override
    public void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) {
        System.out.println("afterEvaluate 触发");
    }

    @Override
    public void onEvaluationError(Rule rule, Facts facts, Exception exception) {
        System.out.println("onEvaluationError 触发");
    }

    @Override
    public void beforeExecute(Rule rule, Facts facts) {
        System.out.println("beforeExecute 触发");
    }

    @Override
    public void onSuccess(Rule rule, Facts facts) {
        System.out.println("onSuccess 触发");
    }

    @Override
    public void onFailure(Rule rule, Facts facts, Exception exception) {
        System.out.println("onFailure 触发");
    }
}

规则类FiveRules:

@Rule(name = "fiveRules", description = "this is fiveRules")
public class FiveRules {

    @Condition
    public boolean isFive(@Fact("number") Integer number){
        System.out.println("触发规则isFive Condition");
//        System.out.println(1/0);
        return number % 5 == 0;
    }

    @Action
    public void isFizz(@Fact("number") Integer number){
        System.out.println(number + "是5的倍数 触发Action");
//        System.out.println(1/0);
    }

    @Priority
    public int getPriority(){
        return 5;
    }
}

规则类SevenRules:

@Rule(name = "sevenRules", description = "this is sevenRules")
public class SevenRules {

    @Condition
    public boolean isSeven(@Fact("number") Integer number){
        System.out.println("触发规则isSeven Condition");
        System.out.println(1/0);
        return number % 7 == 0;
    }

    @Action
    public void then(@Fact("number") Integer number){
        System.out.println(number + " 是7的倍数!触发isSeven action");
    }

    @Priority
    public int getPriority(){
        return 10;
    }
}

执行程序:

要使用监听需要使用DefaultRulesEngine 或 InferenceRulesEngine 规则引擎,使用一般的RulesEngine是没法使用监听功能的,监听器可以设置多个,若设置多个使用registerRuleListeners(List ruleListeners) 参数传入一组监听器即可。

public static void main(String[] args) {

        Rules rules = new Rules();
        rules.register(new SevenRules());
        rules.register(new FiveRules());

        Facts facts = new Facts();
        facts.put("number", 35);

        DefaultRulesEngine engine = new DefaultRulesEngine();
        engine.registerRuleListener(new MyRules());

        engine.fire(rules, facts);
    }

当监听的规则是一组复合规则的时候,监听程序只会作用在这一组规则上,而不是作用于组内的每一个规则,也就是说一组股则所有成功了,才算成功,只要有一个失败过异常,都不会触发成功(onSuccess),有点类似数据库的事务。

符合规则类:

public class FiveOrSevenRules extends UnitRuleGroup{

    public FiveOrSevenRules(Object... rules){
        for (Object rule : rules) {
            this.addRule(rule);
        }
    }

    @Override
    public int getPriority() {
        return 0;
    }
}

执行程序:

public static void main(String[] args) {

        Rules rules = new Rules();
        rules.register(new FiveOrSevenRules(new FiveRules(), new SevenRules()));

        Facts facts = new Facts();

        facts.put("number", 35);

        DefaultRulesEngine engine = new DefaultRulesEngine();

        engine.fire(rules, facts);

    }
引擎监听
监听方法名触发时机
beforeEvaluate规则引擎触发之前执行,即在第一个规则的condition之前,先于规则监听的beforeEvaluate方法
afterExecute所有规则执行完成之后,后于规则监听的所有方法

引擎监听类:

引擎监听类需要实现 RulesEngineListener 类,通过重写beforeEvaluate方法和afterExecute方法实现

public class MyEngineListener implements RulesEngineListener {
    @Override
    public void beforeEvaluate(Rules rules, Facts facts) {
        System.out.println("engine beforeEvaluate 触发");
    }

    @Override
    public void afterExecute(Rules rules, Facts facts) {
        System.out.println("engine afterExecute 触发");
    }
}

规则类和上面规则监听的一样就不重复了

执行程序:

通过向规则引擎注册引擎监听类来进行监听,引擎监听也可以传多个,使用registerRulesEngineListeners(List rulesEngineListeners)方法,参数传入一组监听类即可。

    public static void main(String[] args) {

        Rules rules = new Rules();
        rules.register(new FiveOrSevenRules(new FiveRules(), new SevenRules()));

        Facts facts = new Facts();
        facts.put("number", 35);
        
        DefaultRulesEngine engine = new DefaultRulesEngine();
        engine.registerRulesEngineListener(new MyEngineListener());
        engine.registerRuleListener(new MyRules());

        engine.fire(rules, facts);
    }
表达式语言支持

这个在上面的规则定义已经有了,请移步规则定义

写了点测试代码,有兴趣的可以看一下,点这里查看

Drools

参考另一篇文章:https://blog.csdn.net/qq_41896365/article/details/122233006?spm=1001.2014.3001.5501

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值