这是个广告不要点击哈哈哈

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 会不断的重新进行判断执行,所以必须在满足条件执行的操作中修改自身实例。不然会崩溃

posted on 2021-04-25 17:03  水流花落  阅读(496)  评论(0编辑  收藏  举报