easy-rule 学习
阅读原文时间:2023年07月12日阅读:1

Easyrule是个规则引擎,类似于drools,我们来熟悉一下这个东西

  • [ ] 一个简单实例规则,这个规则会被一直触发,然后行为是打印helloWorld

    @Rule(name="helloWorld",description = "总是打印helloWorld")
    public class HelloWorldRule {
    @Condition
    public boolean when(){
    return true;
    }

    @Action  
    public void then(){  
        System.out.println("hello world");  
    }  

    }

    public class DemoLauncher {
    public static void main(String[] args) {
    Facts facts=new Facts();
    //规则集合定义并注册
    Rules rules=new Rules();
    rules.register(new HelloWorldRule());

        //创建一个规则引擎,并驱动rules  
        RulesEngine rulesEngine=new DefaultRulesEngine();  
                //执行  
        rulesEngine.fire(rules,facts);  
    }  

    } 

    日志打印:
  • hello world

  • 配上日志包,观察下框架的日志

    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'helloWorld', description = '总是打印helloWorld', priority = '2147483646'}
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'helloWorld' triggered
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'helloWorld' performed successfully
    hello world
    
    
    org.slf4j.simpleLogger.defaultLogLevel=debug
  • [ ] FizzBuzz : 数字从一到100 当能被5整除的时候发出fizz,被7整除时候发出buzz,同时被5和7整除就发出fizzbuzz

  • [ ] shop:这个示例展示MVEL表达式在EasyRules中的应用,这里示例我们实现一个功能: 小商店卖酒,不能卖给未成年人(法定年龄小于18岁的人)

    • 定义一个人的对象

      @Data
      public class Person {
      private String name;

      private int age;
      
      private boolean adult;

      }

    • MVEL 表达式来写一个规则,这个规则做两件事,首先判断人是不是18岁以上,如果是我们将人的adult属性修改为true,成年人。买酒的行为判断人是否成年如果未成年则拒绝。

      Rule ageRule=new MVELRule()
                      .name("年龄规则")
                      .description("检查用户年龄是否大于18岁")
                      .priority(1)
                      .when("person.age > 18")
                      .then("person.setAdult(true);");
    • 另外一个规则,是否可以买酒,这次用一个另外的方式来配置规则,写yml文件的方式代码如下:

      name: "alcohol rule"
      description: "小孩子不能喝酒"
      priority: 2
      condition: "person.isAdult()==false"
      # 这里是actions数组类型-容易写成action
      actions:
        - "System.out.println(\\"Shop: Sorry, you are not allowed to buy alcohol\\");"
    • 运行:用MVELRuleFactory加载规则

      public class MvelRuleDemo {
          public static void main(String[] args) throws Exception {
              Rule ageRule=new MVELRule()
                      .name("年龄规则")
                      .description("检查用户年龄是否大于18岁")
                      .priority(1)
                      .when("person.age > 18")
                      .then("person.setAdult(true);");
              //定义工厂类
              MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
              URL url = MvelRuleDemo.class.getClassLoader().getResource("rule/alcohol-rule.yml");
              Rule alcoholRule = ruleFactory.createRule(new FileReader(url.getPath()));
          // 规则合集
          Rules rules=new Rules();
          rules.register(ageRule);
          rules.register(alcoholRule);
      //规则引擎
      RulesEngine rulesEngine=new DefaultRulesEngine();
      // 实例
      System.out.println("来判断接下来的客人能不能买酒");
      Person p=new Person();
      p.setAge(17);
      p.setName("小李");
      
      Facts facts=new Facts();
      facts.put("person",p);
      
      // 执行
      rulesEngine.fire(rules,facts);
      }
      } 来判断接下来的客人能不能买酒 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 } [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules: [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '年龄规则', description = '检查用户年龄是否大于18岁', priority = '1'} [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = '小孩子不能喝酒', priority = '2'} [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts: [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { person : Person(name=小李, age=17, adult=false) } [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' has been evaluated to false, it has not been executed [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' triggered [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' performed successfully Shop: Sorry, you are not allowed to buy alcohol
    • 修改为19岁后执行-执行完打印一下用户信息,发现用户的成年状态被修改了

      来判断接下来的客人能不能买酒
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '年龄规则', description = '检查用户年龄是否大于18岁', priority = '1'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = '小孩子不能喝酒', priority = '2'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { person : Person(name=小李, age=19, adult=false) }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' triggered
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' performed successfully
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' has been evaluated to false, it has not been executed
      Person(name=小李, age=19, adult=true)
    • [ ] InferenceRulesEngine 持续对已知事实应用规则,直到不再应用规则为止,上面的例子们引擎由默认改为这个的话,代码停不下来,可以试一下,源码也可以读一下处理方式由很大不同。


      • default


        @Override
        public void fire(Rules rules, Facts facts) {
        triggerListenersBeforeRules(rules, facts);
        doFire(rules, facts);
        triggerListenersAfterRules(rules, facts);
        }

        void doFire(Rules rules, Facts facts) {
            if (rules.isEmpty()) {
                LOGGER.warn("No rules registered! Nothing to apply");
                return;
            }
            logEngineParameters();
            log(rules);
            log(facts);
            LOGGER.debug("Rules evaluation started");
            for (Rule rule : rules) {
                final String name = rule.getName();
                final int priority = rule.getPriority();
                if (priority > parameters.getPriorityThreshold()) {
                    LOGGER.debug("Rule priority threshold ({}) exceeded at rule '{}' with priority={}, next rules will be skipped",
                            parameters.getPriorityThreshold(), name, priority);
                    break;
                }
                if (!shouldBeEvaluated(rule, facts)) {
                    LOGGER.debug("Rule '{}' has been skipped before being evaluated",
                        name);
                    continue;
                }
                if (rule.evaluate(facts)) {
                    LOGGER.debug("Rule '{}' triggered", name);
                    triggerListenersAfterEvaluate(rule, facts, true);
                    try {
                        triggerListenersBeforeExecute(rule, facts);
                        rule.execute(facts);
                        LOGGER.debug("Rule '{}' performed successfully", name);
                        triggerListenersOnSuccess(rule, facts);
                        if (parameters.isSkipOnFirstAppliedRule()) {
                            LOGGER.debug("Next rules will be skipped since parameter skipOnFirstAppliedRule is set");
                            break;
                        }
                    } catch (Exception exception) {
                        LOGGER.error("Rule '" + name + "' performed with error", exception);
                        triggerListenersOnFailure(rule, exception, facts);
                        if (parameters.isSkipOnFirstFailedRule()) {
                            LOGGER.debug("Next rules will be skipped since parameter skipOnFirstFailedRule is set");
                            break;
                        }
                    }
                } else {
                    LOGGER.debug("Rule '{}' has been evaluated to false, it has not been executed", name);
                    triggerListenersAfterEvaluate(rule, facts, false);
                    if (parameters.isSkipOnFirstNonTriggeredRule()) {
                        LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");
                        break;
                    }
                }
            }
        }</code></pre></li>

      • inferenceRulesEngine: 只是在默认的执行外包装了以下一下代码


        @Override
        public void fire(Rules rules, Facts facts) {
        Set<Rule> selectedRules;
        do {
        LOGGER.debug("Selecting candidate rules based on the following facts: {}", facts);
        selectedRules = selectCandidates(rules, facts);
        if(!selectedRules.isEmpty()) {
        // 这个delegate就是上面默认的规则引擎
        delegate.fire(new Rules(selectedRules), facts);
        } else {
        LOGGER.debug("No candidate rules found for facts: {}", facts);
        }
        } while (!selectedRules.isEmpty());
        }

        private Set&lt;Rule&gt; selectCandidates(Rules rules, Facts facts) {
            Set&lt;Rule&gt; candidates = new TreeSet&lt;&gt;();
            for (Rule rule : rules) {
                if (rule.evaluate(facts)) {
                    candidates.add(rule);
                }
            }
            return candidates;
        }</code></pre></li></ul>

        示例展示一个空调系统,当温度过高时不断降温操作直至温度降低到合适的度数,

        • 创建一个条件类,来决定什么时候是热

          public class HighTemperatureConditon implements org.jeasy.rules.api.Condition {
              // 中文意思评估评定-
              @Override
              public boolean evaluate(Facts facts) {
                  Integer temperature=facts.get("temperature");
              return temperature&gt;25;
          }
          
          static HighTemperatureConditon itIsHot(){
              return new HighTemperatureConditon();
          }
          }
        • action类,满足条件后的执行内容

          public class DecreaseTemperactureAction implements org.jeasy.rules.api.Action {
              @Override
              public void execute(Facts facts) throws Exception {
                  System.out.println("温度过高-降温");
                  Integer temperature=facts.get("temperature");
                  facts.put("temperature",temperature-1);
              }
              static DecreaseTemperactureAction decreaseTemperacture(){
                  return new DecreaseTemperactureAction();
              }
          }
        • 执行类-我们注册规则指定规则的触发条件为温度过高,rule.evaluate 方法,然后then执行的结果是:action.execute

          public class AirLauncherDemo {
              public static void main(String[] args) {
                  Facts facts=new Facts();
                  facts.put("temperature",30);
              // 规则
              Rule airRule=  new RuleBuilder()
                      .name("空调测试")
                      .when(HighTemperatureConditon.itIsHot())
                      .then(DecreaseTemperactureAction.decreaseTemperacture())
                      .build();
          Rules rules=new Rules();
          rules.register(airRule);
          
          //inference引擎,持续不断的执行
          RulesEngine rulesEngine=new InferenceRulesEngine();
          
          rulesEngine.fire(rules,facts);
          System.out.println(facts.get("temperature").toString());
          }
          }
        • 日志-我们发现一直降温到25度

          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 30 } ]
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 30 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 29 } ]
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 29 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 28 } ]
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 28 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 27 } ]
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 27 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 26 } ]
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 26 }
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
          [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 25 } ]
          [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - No candidate rules found for facts: [ { temperature : 25 } ]
          温度过高-降温
          温度过高-降温
          温度过高-降温
          温度过高-降温
          温度过高-降温
          25

        这个示例说明,InferenceRulesEngine 会不断的重新进行判断执行,所以必须在满足条件执行的操作中修改自身实例。不然会崩溃

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章