zoukankan      html  css  js  c++  java
  • easy-rule 学习

    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

      1. java简单实现:循环然后用ifelse判断该怎么处理

        public class JavaDeme {
            public static void main(String[] args) {
                for(int i=0;i<100;i++){
                    if(i%5==0&&i%7==0){
                        System.out.println("fizzbuzz"+":"+i);
                    }else if(i%5==0){
                        System.out.println("fizz:"+i);
                    }else if(i%7==0){
                        System.out.println("buzz:"+i);
                    }else{
                        //System.out.println("啥也不是"+i);
                    }
                  //  System.out.println();
                }
            }
        }
        
      2. easyrule实现先为每个规则写个rule

        • FizzRule

          @Rule
          public class FizzRule {
          
              @Condition
              public boolean isFizz(@Fact("number") Integer number) {
                  return number % 5 == 0;
              }
          
              @Action
              public void printFizz() {
                  System.out.print("fizz");
              }
          		// 优先级为1
              @Priority
              public int getPriority() {
                  return 1;
              }
          }
          
        • BuzzRule

          @Rule
          public classBuzzRule {
          
              @Condition
          public booleanisBuzz(@Fact("number") Integer number) {
          returnnumber % 7 == 0;
              }
          
              @Action
          public voidprintBuzz() {
                  System.out.print("buzz");
              }
              //优先级2
              @Priority
          public intgetPriority() {
          return2;
              }
          }
          
        • FizzBuzzRule :BuzzRule,和FizzRule 整合的规则

          public class FizzBuzzRule extends UnitRuleGroup {
              public FizzBuzzRule(Object... rules){
                  for(Object rule:rules){
                      addRule(rule);
                  }
              }
          
              @Override
              public int getPriority(){
                  return 0;
              }
          }
          
        • 两个规则都不符合

          @Rule
          public class NonFizzBuzzRule {
              @Condition
              public boolean isNotFizzNorBuzz(@Fact("number") Integer number){
                  // can return true, because this is the latest rule to trigger according to assigned priorities
                  // and in which case, the number is not fizz nor buzz
                  return number % 5 != 0 || number % 7 != 0;
              }
              @Action
              public void printInput(@Fact("number") Integer number) {
                  System.out.print(number);
              }
          
              @Priority
              public int getPriority() {
                  return 3;
              }
          }
          
        • 主方法入口:

          public class FizzBuzzWithEasyRules {
              public static void main(String[] args) {
                  RulesEngineParameters parameters=new RulesEngineParameters();
                  // 满足第一个规则就退出
                  parameters.setSkipOnFirstAppliedRule(true);
          
                  // 引擎
                  RulesEngine rulesEngine=new DefaultRulesEngine();
          				//RulesEngine rulesEngine=new DefaultRulesEngine(parameters);
          
                  // 规则
                  Rules rules=new Rules();
                  rules.register(new FizzRule());
                  rules.register(new BuzzRule());
                  rules.register(new FizzBuzzRule(new FizzRule(),new BuzzRule()));
                  rules.register(new NonFizzBuzzRule());
          
                  //匹配规则
                  Facts facts=new Facts();
                  for(int i=0;i<100;i++){
                      facts.put("number",i);
                      rulesEngine.fire(rules,facts);
                      System.out.println();
                  }
          
              }
          }
          
        • 日志

          31
          32
          33
          34
          fizzbuzzfizzbuzz  // 这里打印了两边,因为引擎参数没有把跳出判断加上
          36
          37
          38
          39
          fizz40
          
          31
          32
          33
          34
          fizzbuzz
          36
          37
          38
          
    • [ ] 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;
                          }
                      }
                  }
              }
          
        • 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<Rule> selectCandidates(Rules rules, Facts facts) {
                  Set<Rule> candidates = new TreeSet<>();
                  for (Rule rule : rules) {
                      if (rule.evaluate(facts)) {
                          candidates.add(rule);
                      }
                  }
                  return candidates;
              }
          

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

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

          public class HighTemperatureConditon implements org.jeasy.rules.api.Condition {
              // 中文意思评估评定-
              @Override
              public boolean evaluate(Facts facts) {
                  Integer temperature=facts.get("temperature");
          
                  return temperature>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 会不断的重新进行判断执行,所以必须在满足条件执行的操作中修改自身实例。不然会崩溃

  • 相关阅读:
    .Net中DataGridview数据如何导出到excel表
    SQLSEVER 中的那些键和约束
    数据仓库中数据粒度
    详解三层架构图
    三层概念总结
    SQL Sever 2008配置工具中过程调用失败解决方法
    设计模式之中介者模式
    设计模式之访问者模式
    设计模式之代理模式
    设计模式之迭代器模式
  • 原文地址:https://www.cnblogs.com/shuiliuhualuo/p/14701048.html
Copyright © 2011-2022 走看看