规则引擎Easy-rules

官网源码:https://github.com/j-easy/easy-rules
官网案例:https://github.com/j-easy/easy-rules/wiki/fizz-buzz
介绍:
规则引擎是为了解决业务代码和业务规则分离的引擎,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离,其实就是将一大堆if/else进行处理,Easy Rules 所做的,它提供了Rule创建具有条件和操作的规则的抽象,以及RulesEngine通过一组规则运行以评估条件和执行操作的API

核心功能:

  1. 轻量级库和易于学习的 API
  2. 带有注解编程模型的基于 POJO 的开发
  3. 用于定义业务规则并通过 Java 轻松应用它们的有用抽象
  4. 从原始规则创建复合规则的能力
  5. 使用表达式语言(如 MVEL、SpEL 和 JEXL)定义规则的能力

一个规则由名称、描述、优先级三个属性和判断、执行两个方法组成,实现Rule接口,
和使用@Rule,@Condition,@Action,@Priority,@Fact注解的效果是一样的。

它主要包括几个主要的类或接口:Rule,RulesEngine,RuleListener,Facts
还有几个主要的注解:@Action,@Condition,@Fact,@Priority,@Rule

  1. Rule
public interface Rule extends Comparable<Rule> {

    /**
     * 默认的规则名称
     */
    String DEFAULT_NAME = "rule";

    /**
     * 默认的规则描述
     */
    String DEFAULT_DESCRIPTION = "description";

    /**
     * 默认的规则优先级
     */
    int DEFAULT_PRIORITY = Integer.MAX_VALUE - 1;

    getter and setter...

    /**
     * 规则引擎判断条件
     * 如果提供的facts被应用到规则上返回true,否则返回false
     */
    boolean evaluate(Facts facts);

    /**
     * 规则引擎判断条件返回true后,执行此方法
     */
    void execute(Facts facts) throws Exception;

}
  1. RulesEngine负责检查和开启规则,同时可以得到规则引擎的参数和规则监听器列表
public interface RulesEngine {

    /**
     * 返回规则引擎的参数
     */
    RulesEngineParameters getParameters();

    /**
     * 返回已注册的规则监听器的列表
     */
    List<RuleListener> getRuleListeners();

    /**
     * 在给定的因素上开启所有已注册的规则
     */
    void fire(Rules rules, Facts facts);

    /**
     * 检查规则和因素是否符合
     */
    Map<Rule, Boolean> check(Rules rules, Facts facts);
}
  1. RuleListener在规则执行的4个阶段加上了触发器,可以灵活地控制规则执行结果
    (定义规则监听器通过实现RuleListener接口)
public interface RuleListener {

    /**
     * 规则条件判断之前的触发器
     */
    boolean beforeEvaluate(Rule rule, Facts facts);

    /**
     * 规则条件判断之后的触发器
     */
    void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult);

    /**
     * 规则执行之前的触发器
     */
    void beforeExecute(Rule rule, Facts facts);

    /**
     * 规则执行成功之后的触发器
     */
    void onSuccess(Rule rule, Facts facts);

    /**
     * 规则执行失败之后的触发器
     */
    void onFailure(Rule rule, Facts facts, Exception exception);

}
  1. Facts就是一个hashmap,通过注解@Fact(String value),其中的value是map的key,可以拿到Facts中的value
public class Facts implements Iterable<Map.Entry<String, Object>> {

    private Map<String, Object> facts = new HashMap<>();

    /**
     * 在工作空间放置一个因素
     */
    public Object put(String name, Object fact) {
        Objects.requireNonNull(name);
        return facts.put(name, fact);
    }

    /**
     * 删除因素
     */
    public Object remove(String name) {
        Objects.requireNonNull(name);
        return facts.remove(name);
    }

    /**
     * 通过name得到因素
     */
    public Object get(String name) {
        Objects.requireNonNull(name);
        return facts.get(name);
    }

    /**
     * 以map形式返回因素
     */
    public Map<String, Object> asMap() {
        return facts;
    }
    ...
}

一. pom.xml中引入maven依赖

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


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

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

二. 定义规则

大多数业务规则可以由以下定义表示:

  1. 名称:规则命名空间中的唯一规则名称
  2. 说明:规则的简要说明
  3. 优先级:相对于其他规则的规则优先级
  4. 事实:去匹配规则时的一组已知事实
  5. 条件:为了匹配该规则,在给定某些事实的情况下应满足的一组条件
  6. 动作:当条件满足时要执行的一组动作(可以添加/删除/修改事实)

Easy Rules为定义业务规则的每个关键点提供了抽象。

public interface Rule {

    /**
    * 改方法封装规则的条件(conditions)
    * @return 如果提供的事实适用于该规则返回true, 否则,返回false
    */
    boolean evaluate(Facts facts);

    /**
    * 改方法封装规则的操作(actions)
    * @throws 如果在执行过程中发生错误将抛出Exception
    */
    void execute(Facts facts) throws Exception;

    //Getters and setters for rule name, description and priority omitted.

}

evaluate方法封装了必须求值为TRUE才能触发规则的条件。
execute方法封装了在满足规则条件时应执行的操作。条件和动作ConditionandAction接口表示。

首先,定义规则,方式有多种

方式一:注解

  1. @Condition注解指定规则条件
  2. @Fact注解指定参数
  3. @Action注解指定规则执行的动作
@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!");
    }
}

@Condition注解标记计算规则条件的方法。此方法必须是公共的,可以有一个或多个用@Fact注解的参数,并返回布尔类型。只有一个方法能用@Condition注解。

@Action注解标记要执行规则操作的方法。规则可以有多个操作。可以使用order属性按指定的顺序执行操作。默认情况下,操作的顺序为0。

方式二:链式编程

Rule rule = new RuleBuilder()
                .name("myRule")
                .description("myRuleDescription")
                .priority(3)
                .when(condition)
                .then(action1)
                .then(action2)
                .build();

在这个例子中, Condition实例condition,Action实例是action1和action2。

方式三:表达式

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

方式四:yml配置文件
例如:weather-rule.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"));

组合规则

CompositeRule由一组规则组成。这是一个典型地组合设计模式的实现。

组合规则是一个抽象概念,因为可以以不同方式触发组合规则。

Easy Rules自带三种CompositeRule实现:

UnitRuleGroup : 要么应用所有规则,要么不应用任何规则(AND逻辑)
ActivationRuleGroup : 它触发第一个适用规则,并忽略组中的其他规则(XOR逻辑)
ConditionalRuleGroup : 如果具有最高优先级的规则计算结果为true,则触发其余规则
复合规则可以从基本规则创建并注册为常规规则:

//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);

每个规则都有优先级。它代表触发注册规则的默认顺序。默认情况下,较低的值表示较高的优先级。可以重写compareTo方法以提供自定义优先级策略。

定义事实
Facts API是一组事实的抽象,在这些事实上检查规则。
在内部,Facts实例持有HashMap<String,Object>,这意味着:
事实需要命名,应该有一个唯一的名称,且不能为空
任何Java对象都可以充当事实
这里有一个实例定义事实:

// define facts
Facts facts = new Facts();
facts.add("rain", true);

用@Fact注解可以将Facts注入到condition和action方法中
在下面的规则中,rain 事实被注入itRains方法的rain参数:

@Rule
class WeatherRule {

    @Condition
    public boolean itRains(@Fact("rain") boolean rain) {
        return rain;
    }

    @Action
    public void takeAnUmbrella(Facts facts) {
        System.out.println("It rains, take an umbrella!");
        // can add/remove/modify facts
    }

}

Facts类型参数 被注入已知的 facts中 (像action方法takeAnUmbrella一样).

如果缺少注入的fact, 这个引擎会抛出 RuntimeException异常.
定义规则引擎
从版本3.1开始,Easy Rules提供了RulesEngine接口的两种实现:

  1. DefaultRulesEngine:根据规则的自然顺序(默认为优先级)应用规则。
  2. InferenceRulesEngine:持续对已知事实应用规则,直到不再应用规则为止。

创建一个规则引擎
要创建规则引擎,可以使用每个实现的构造函数:

RulesEngine rulesEngine = new DefaultRulesEngine();
// or
RulesEngine rulesEngine = new InferenceRulesEngine();

然后,您可以按以下方式触发注册规则:

rulesEngine.fire(rules, facts);

规则引擎参数

Easy Rules 引擎可以配置以下参数:

Parameter	Type	Required	Default
rulePriorityThreshold	int	no	MaxInt
skipOnFirstAppliedRule	boolean	no	false
skipOnFirstFailedRule	boolean	no	false
skipOnFirstNonTriggeredRule	boolean	no	false

skipOnFirstAppliedRule:告诉引擎规则被触发时跳过后面的规则。
skipOnFirstFailedRule:告诉引擎在规则失败时跳过后面的规则。
skipOnFirstNonTriggeredRule:告诉引擎一个规则不会被触发跳过后面的规则。
rulePriorityThreshold:告诉引擎如果优先级超过定义的阈值,则跳过下一个规则。版本3.3已经不支持更改,默认MaxInt。
可以使用RulesEngineParameters API指定这些参数:

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

RulesEngine rulesEngine = new DefaultRulesEngine(parameters);

如果要从引擎获取参数,可以使用以下代码段:

RulesEngineParameters parameters = myEngine.getParameters();

这允许您在创建引擎后重置引擎参数。

开始测试案例
1.创建项目(通过maven骨架创建)

mvn archetype:generate \
    -DarchetypeGroupId=org.jeasy \
    -DarchetypeArtifactId=easy-rules-archetype \
    -DarchetypeVersion=4.0.0

在这里插入图片描述
在这里插入图片描述
创建完成后,会默认生成一个HelloWorldRule规则
在这里插入图片描述
入过启动报错 Error:(26, 34) java: 程序包org.jeasy.rules.annotation不存在
在这里插入图片描述
File -->settings —>maven —>Runner ,勾选:Dele… 然后保存
在这里插入图片描述
重写启动
在这里插入图片描述
依赖:
在这里插入图片描述

测试案例一:
在这里插入图片描述

1.用到的实体

package org.testRule.one;

/**
 * @author: YXY
 * @date: 2021/6/23 15:22
 * @Version 1.0
 */
public class User {

    private Integer age;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

2.测试类

package org.testRule.one;

import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRule;

import java.util.HashMap;
import java.util.Map;

/**
 * @author: YXY
 * @date: 2021/6/23 15:21
 * @Version 1.0
 */
public class MVELTestRule {

    public static void main(String[] args) {

        //规则引擎
        RulesEngine rulesEngine = new DefaultRulesEngine();
        //规则
        MVELRule ageRule = new MVELRule()
                .name("my rule")
                .description("test demo rule")
                .priority(1)
                .when("user.age > 18")
                .then("map.put('code',200);map.put('msg','success');");



        Rules rules = new Rules();
        rules.register(ageRule);

        Facts facts = new Facts();

        User user   = new User();
        user.setAge(19);
        facts.put("user",user);
        Map map  = new HashMap();

        facts.put("map",map);

        rulesEngine.fire(rules,facts);
        System.out.println(map);
    }
}

3.运行结果
在这里插入图片描述
测试案例二:
在这里插入图片描述
在这里插入图片描述
1.定义规则

package org.testRule.tow.rules;

import org.jeasy.rules.annotation.*;

/**
 * @author: YXY
 * @date: 2021/6/23 15:19
 * @Version 1.0
 */
@Rule(name = "被2整除")
public class TwoRule {

    @Condition
    public boolean isTwo(@Fact("num") int num){
        System.out.println("---isTwo----run----");
        return num % 2 == 0;
    }

    @Action
    public void action(@Fact("num") int num){
        System.out.println(num + " 被2整除");
    }

    @Priority
    public int getPriority(){
        return 1;
    }

}

package org.testRule.tow.rules;

import org.jeasy.rules.annotation.*;

/**
 * @author: YXY
 * @date: 2021/6/23 15:19
 * @Version 1.0
 */
@Rule(name = "被3整除")
public class ThreeRule {
    @Condition //条件判断注解:如果return true, 执行Action
    public boolean isThree(@Fact("num") int num){
        System.out.println("---isThree----run----");
        return num % 3 == 0;
    }

    @Action
    public void action(@Fact("num") int num){
        System.out.println(num + " 被3整除");
    }

    @Priority //优先级注解:return 数值越小,优先级越高
    public int getPriority(){
        return 2;
    }
}

package org.testRule.tow.rules;

import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.support.composite.UnitRuleGroup;

/**
 * @author: YXY
 * @date: 2021/6/23 15:19
 * @Version 1.0
 */
@Rule(name = "被2和3同时整除")
public class TwoThreeRuleUnitGroup extends UnitRuleGroup {

    public TwoThreeRuleUnitGroup(Object... rules) {
        for (Object rule : rules) {
            addRule(rule);
        }
    }


    @Override
    public int getPriority() {
        return 0;
    }
}

package org.testRule.tow.rules;

import org.jeasy.rules.annotation.*;

/**
 * @author: YXY
 * @date: 2021/6/23 15:20
 * @Version 1.0
 */
@Rule(name = "既不被2整除也不被3整除")
public class OtherRule {
    @Condition
    public boolean isOther(@Fact("num") int num){
        System.out.println("---isOther----run----");
        return num % 2 != 0 && num % 3 != 0;
    }

    @Action
    public void action(@Fact("num") int num){
        System.out.print(num);
    }

    @Priority
    public int getPriority(){
        return 3;
    }
}

2.测试类

package org.testRule.tow;

import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.testRule.tow.rules.OtherRule;
import org.testRule.tow.rules.ThreeRule;
import org.testRule.tow.rules.TwoRule;
import org.testRule.tow.rules.TwoThreeRuleUnitGroup;

/**
 * @author: YXY
 * @date: 2021/6/23 15:21
 * @Version 1.0
 */


public class RuleTest {
    public static void main(String[] args) {
        RulesEngine rulesEngine = new DefaultRulesEngine();
        //创建规则
        Rules rules = new Rules();
        rules.register(new TwoRule());
        rules.register(new ThreeRule());
        rules.register(new TwoThreeRuleUnitGroup(new TwoRule(), new ThreeRule()));
        rules.register(new OtherRule());
        //设置真实数据
        Facts facts = new Facts();
        for (int i=1 ; i<=10 ; i++){
            //规则因素,对应的name,要和规则里面的@Fact 一致
            facts.put("num", i);
            //执行规则
            rulesEngine.fire(rules, facts);
            System.out.println();
        }
    }
}


3.运行结果
在这里插入图片描述
控制台乱码解决:

-Dfile.encoding=UTF-8

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Easy-rules是一个轻量级的Java规则引擎,可以帮助我们在应用程序中使用规则来进行业务逻辑处理。在Spring-boot中使用Easy-rules需要以下步骤: 1. 添加Easy-rules依赖 在pom.xml文件中添加Easy-rules依赖: ```xml <dependency> <groupId>org.easyrules</groupId> <artifactId>easy-rules-core</artifactId> <version>4.1.0</version> </dependency> ``` 2. 创建规则 创建一个规则类,继承自`org.easyrules.core.BasicRule`,并实现`org.easyrules.api.Rules`接口中的方法。例如: ```java public class AdultRule extends BasicRule { private Person person; public AdultRule(Person person) { super("AdultRule", "Check if person is an adult", 1); this.person = person; } @Override public boolean evaluate() { return person.getAge() >= 18; } @Override public void execute() throws Exception { System.out.println(person.getName() + " is an adult"); } } ``` 3. 配置规则引擎 在Spring-boot的配置类中配置规则引擎: ```java @Configuration public class RuleEngineConfiguration { @Bean public RulesEngine rulesEngine() { return new DefaultRulesEngine(); } } ``` 4. 执行规则 在需要执行规则的地方,注入规则引擎,然后将规则添加到规则引擎中并执行: ```java @Autowired private RulesEngine rulesEngine; public void executeRules(Person person) { Rules rules = new Rules(); rules.register(new AdultRule(person)); rulesEngine.fire(rules); } ``` 这样就可以在Spring-boot中使用Easy-rules规则引擎了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值