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