美文网首页
java规则引擎easy-rules使用指南 1 - 基本用法

java规则引擎easy-rules使用指南 1 - 基本用法

作者: bailiyi | 来源:发表于2022-03-29 09:05 被阅读0次

    规则引擎能干什么

    规则引擎的工作方式有点像if-else,它允许你设置一些条件和动作,然后在程序运行时判断某些动作该不该执行。
    easy-rules是一款轻量级的java规则引擎,目前它的长期支持版本是4.1.x,所以我们就以4.1.0版本来看一下如何使用。

    如何引入

    如果使用maven,可以直接在pom中加入:

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

    如果需要对MVEL, SpEL和JEXL表达式的支持,还需要引入相应的支持包:

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

    一个简单的例子

    使用easy-rules非常简单,只需要两个步骤:

    • 创建规则和动作
    • 运行引擎

    以下是一个简单的例子:

    public class Test {
        public static void main(String[] args) {
                // define rules 
                    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();
            Rules rules = new Rules();
            rules.register(weatherRule);
            
            // define facts
            Facts facts = new Facts();
            facts.put("rain", true);
    
            // fire rules on known facts
            RulesEngine rulesEngine = new DefaultRulesEngine();
            rulesEngine.fire(rules, facts);
        }
    }
    

    例子中的weatherRule是构建的条件和动作,其中“when”里面的是条件,“then”里面的是满足条件后需要执行的动作。
    facts是运行中实际的数据。
    这个例子会在控制台打印出:It rains, take an umbrella!

    如何使用Rule

    1 介绍

    Rule用于定义规则和行为,它可以设置以下这些属性:

    • name: 命名空间中的唯一规则名称
    • description: 描述
    • priority: 优先级
    • when:规则
    • then:行为

    当when中的表达式返回true时,将执行then中的表达式。
    then里面除了可以执行方法外,也可以修改Facts里面的数据。

    2 Rule的多种写法

    easy-rules提供了多种定义Rule的写法,还是以上面的例子举例,下面的Rule写法与上面例子中的写法是等价的。

    2.1 使用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();
    

    2.2 使用注解

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

    2.3 使用表达式语言

    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!\");");
    

    使用表达式语言需要引入对应的支持包,比如这里使用了MVEL,那么需要在pom中引入easy-rules-mvel这个包

    2.4 使用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("weather-rule.yml"));
    

    3 复合规则

    有时候我们需要把多个规则放在一起使用,就好像写多层if-else一样。
    easy-rules为此提供了三个对象来支持复合规则的使用:

    • UnitRuleGroup:要么应用所有rule,要么不应用任何rule。
    • ActivationRuleGroup:它触发第一个适用的rule并忽略组中的其他rule(XOR 逻辑)。rule首先按其在组内的自然顺序排序,如果设置了priority,那么数字越小的优先级越高。
    • ConditionalRuleGroup::只有具有最高优先级的rule评估为真,才触发其余rule。

    下面是使用示范:

    //Create a composite rule from two primitive rules
    UnitRuleGroup myUnitRuleGroup =
        new UnitRuleGroup("myUnitRuleGroup", "unit of myRule1 and myRule2");
    myUnitRuleGroup.addRule(myRule1);
    myUnitRuleGroup.addRule(myRule2);
    
    //Register the composite rule as a regular rule
    Rules rules = new Rules();
    rules.register(myUnitRuleGroup);
    
    RulesEngine rulesEngine = new DefaultRulesEngine();
    rulesEngine.fire(rules, someFacts);
    

    如何使用facts

    Fact是用来装需要判断的数据的,它的API定义如下:

    public class Fact<T> {
       private final String name;
       private final T value;
    }
    

    使用的时候直接用Facts,就跟Map用法差不多:

    Facts facts = new Facts();
    facts.put("foo", "bar");
    

    Rule的“then”代码中可以修改facts的数据,可以使用这个特性来获取返回值。
    例如:

    Rule ageRule = new MVELRule()
            .name("age rule")
            .description("Check if person's age is > 18 and marks the person as adult")
            .priority(1)
            .when("person.age > 18")
            .then("person.setAdult(true);");
    

    注意:

    • 如果when方法中缺少注入的Fact,引擎将记录一个警告并认为条件评估为false。
    • 如果then方法中缺少注入的Rule,则不会执行该操作,并且引擎将抛出一个org.jeasy.rules.core.NoSuchFactException.

    如何使用Engine

    1 Engine的两种实现

    Easy Rules 提供了两种RulesEngine接口实现:

    DefaultRulesEngine:根据其自然顺序应用规则(默认为优先级)。
    InferenceRulesEngine:不断地对已知事实应用规则,直到不再适用规则为止。

    DefaultRulesEngine的作用很好理解,就像上面那些例子表现出来的一样。
    InferenceRulesEngine则相当于在DefaultRulesEngine的基础上加了一个循环。还是以开头的代码举例,换成InferenceRulesEngine。
    这时控制台将重复打印“It rains, take an umbrella!”。

    public class Test {
        public static void main(String[] args) {
                // define rules 
                    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();
            Rules rules = new Rules();
            rules.register(weatherRule);
            
            // define facts
            Facts facts = new Facts();
            facts.put("rain", true);
    
            // fire rules on known facts
            RulesEngine rulesEngine = new InferenceRulesEngine();
            rulesEngine.fire(rules, facts);
        }
    }
    

    2 Engine的配置参数

    Engine支持以下几个参数配置:

    范围 类型 必需的 默认
    rulePriorityThreshold int no MaxInt
    skipOnFirstAppliedRule boolean no false
    skipOnFirstFailedRule boolean no false
    skipOnFirstNonTriggeredRule boolean no false
    • skipOnFirstAppliedRule:在应用规则时跳过下一个规则。
    • skipOnFirstFailedRule:在规则失败时跳过下一个规则。
    • skipOnFirstNonTriggeredRule:在未触发规则时跳过下一个规则。
    • rulePriorityThreshold:priority 大于rulePriorityThreshold时跳过下一个规则。

    写法如下:

    RulesEngineParameters parameters = new RulesEngineParameters()
        .rulePriorityThreshold(10)
        .skipOnFirstAppliedRule(true)
        .skipOnFirstFailedRule(true)
        .skipOnFirstNonTriggeredRule(true);
    
    RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
    

    本文由博客一文多发平台 OpenWrite 发布!

    相关文章

      网友评论

          本文标题:java规则引擎easy-rules使用指南 1 - 基本用法

          本文链接:https://www.haomeiwen.com/subject/kalvjrtx.html