Easy Rules规则引擎(下)- 使用

516 阅读4分钟

前言

这一章简单介绍一下此组件的使用方式,当然,在其github首页也有介绍,不过不是很全面,所以在此稍作补充。

Maven引用

        <!--easy rules核心库-->
        <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-core</artifactId>
            <version>4.1.0</version>
        </dependency>

        <!--规则定义文件格式,支持json,yaml等-->
        <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-support</artifactId>
            <version>4.1.0</version>
        </dependency>

        <!--支持mvel规则语法库-->
        <dependency>
            <groupId>org.jeasy</groupId>
            <artifactId>easy-rules-mvel</artifactId>
            <version>4.1.0</version>
        </dependency>

创建规则

priority属性一定要设置,否则默认为2147483646,如果设定了阈值,则业务规则不会被触发,需要特别注意。

注解方式

主要有三个注解【@Rule】、【@Condition】、【@Action】,其中action注解有order顺序设置,可以根据业务需求,预设执行顺序。

@Rule(name = "test-1", priority = 9,description = "注解规则测试")
public class MyRule {

    /**
     * 条件
     * @return 是否满足触发条件
     */
    @Condition
    public boolean when(@Fact("age") int age) {
        System.out.println("执行第一个条件。");
        return age > 19;
    }

    @Action(order = 2)
    public void execBiz1() {
        System.out.println("执行第一个业务。");
    }

    @Action(order = 1)
    public void execBiz2() {
        System.out.println("执行第二个业务。");
    }
}

注意,只能有一个条件,否则报错:
Rule 'com.netease.ot.job.MyRule' must have exactly one method annotated with 'org.jeasy.rules.annotation.Condition'
如果返回false,则输出日志:Rule 'test-1' has been evaluated to false, it has not been executed

Builder方式

        // builder创建规则
        Rule codeRule = new RuleBuilder()
                .name("builder-rule")
                .description("这是Builder规则")
                .priority(5)
                .when(factSet -> (int) factSet.get("age") > 18)
                .then(factSet -> System.out.println("builder rule 被触发1,年龄大于18."))
                .then(factSet -> System.out.println("builder rule 被触发2,年龄大于18."))
                .build();

表达式

        // 表达式规则
        Rule elRule = new MVELRule()
                .name("el-rule")
                .priority(8)
                .description("这是表达式规则")
                .when("age > 15")
                .then("System.out.println("el rule 被触发,年龄大于15.");");

监听器

规则

这里需要注意的只有beforeEvaluate事件,这个方法返回值为false,其结果决定了规则是否可以评估通过,如果返回false,afterEvaluate监听事件也不会被执行。

public class MyRuleListener implements RuleListener {
    @Override
    public boolean beforeEvaluate(Rule rule, Facts facts) {
        System.out.println("规则评估前触发");
        // 注意这个返回值,也决定了规则是否可以评估通过,如果返回false,afterEvaluate监听事件也不会被执行
        return (int) facts.get("age") > 10;
    }
    @Override
    public void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) {
        System.out.println("规则评估后触发,评估是否通过:" + evaluationResult);
    }
    @Override
    public void onEvaluationError(Rule rule, Facts facts, Exception exception) {
        System.out.println("规则评估失败触发");
    }
    @Override
    public void beforeExecute(Rule rule, Facts facts) {
        System.out.println("规则执行前触发");
    }
    @Override
    public void onSuccess(Rule rule, Facts facts) {
        System.out.println("规则成功后触发");
    }
    @Override
    public void onFailure(Rule rule, Facts facts, Exception exception) {
        System.out.println("规则失败后触发");
    }
}

引擎

与规则监听器相比,引擎监听器则无需注意什么了,可以当成是引擎的一个截面,输出日志或者进行特殊业务调整。比如在监听器里进行规则评估,通知相关利益人满足条件的规则;或者动态添加事实或者规则,用来应对突发情况。

public class MyRulesEngineListener implements RulesEngineListener {
    @Override
    public void beforeEvaluate(Rules rules, Facts facts) {
        System.out.println("引擎监听,评估前触发。");
    }
    @Override
    public void afterExecute(Rules rules, Facts facts) {
        System.out.println("引擎监听,执行后触发。");
    }
}

例子

        // 创建因子
        Facts facts = new Facts();
        facts.add(new Fact<>("age", 28));
        // 规则集合
        Rules rules = new Rules();
        // 添加注解规则
        rules.register(new MyRule());
        rules.register(new TestRule());
        // builder创建规则
        Rule codeRule = new RuleBuilder()
                .name("builder-rule")
                .description("这是代码规则")
                .priority(5)
                .when(factSet -> (int) factSet.get("age") > 18)
                .then(factSet -> System.out.println("builder rule 被触发1,年龄大于18."))
                .then(factSet -> System.out.println("builder rule 被触发2,年龄大于18."))
                .build();
        rules.register(codeRule);
        // 表达式规则
        Rule elRule = new MVELRule()
                .name("el-rule")
                .priority(9)
                .description("这是表达式规则")
                .when("age > 15")
                .then("System.out.println("el rule 被触发,年龄大于15.");");
        rules.register(elRule);

        // 创建引擎参数
        RulesEngineParameters parameters = new RulesEngineParameters()
                // 告诉引擎如果优先级超过定义的阈值,则跳过下一个规则
                .priorityThreshold(10)
                // 当一个规则触发之后,是否跳过之后所有的规则
                .skipOnFirstAppliedRule(false)
                // 当一个规则失败之后,是否跳过之后所有的规则
                .skipOnFirstFailedRule(true)
                // 当第一个规则没有触发,是否跳过之后所有的规则
                .skipOnFirstNonTriggeredRule(false);
        // 创建引擎
        DefaultRulesEngine defaultEngine = new DefaultRulesEngine(parameters);
        defaultEngine.registerRuleListener(new MyRuleListener());
        defaultEngine.registerRulesEngineListener(new MyRulesEngineListener());
        defaultEngine.fire(rules, facts);

输出

引擎监听,评估前触发。
17:14:08.265 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = true, priorityThreshold = 10 }
17:14:08.269 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
17:14:08.274 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'test-2', description = 'when when then execBiz2', priority = '2'}
17:14:08.274 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'builder-rule', description = '这是代码规则', priority = '5'}
17:14:08.274 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'el-rule', description = '这是表达式规则', priority = '9'}
17:14:08.274 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'test-1', description = '注解规则测试', priority = '9'}
17:14:08.275 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
17:14:08.275 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact{name='age', value=28}
17:14:08.275 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
规则评估前触发
17:14:08.282 [main] WARN org.jeasy.rules.core.RuleProxy - Rule 'com.netease.ot.job.TestRule' has been evaluated to false due to a declared but missing fact 'rain' in [Fact{name='age', value=28}]
17:14:08.282 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'test-2' has been evaluated to false, it has not been executed
规则评估后触发,评估是否通过:false
规则评估前触发
17:14:08.285 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'builder-rule' triggered
规则评估后触发,评估是否通过:true
规则执行前触发
builder rule 被触发1,年龄大于18.
builder rule 被触发2,年龄大于18.
17:14:08.285 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'builder-rule' performed successfully
规则成功后触发
规则评估前触发
17:14:08.318 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'el-rule' triggered
规则评估后触发,评估是否通过:true
规则执行前触发
el rule 被触发,年龄大于15.
17:14:08.326 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'el-rule' performed successfully
规则成功后触发
规则评估前触发
执行第一个条件。
17:14:08.327 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'test-1' triggered
规则评估后触发,评估是否通过:true
规则执行前触发
执行第二个业务。
执行第一个业务。
17:14:08.327 [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'test-1' performed successfully
规则成功后触发
引擎监听,执行后触发。