Easy Rule的使用
Easy Rule介绍
对于Easy Rule是什么,本人无法给出具体的定义。只是说一下自己的理解,它是一个简单而强大的规则引擎,你可以自定义condition与action来组合实现一个自己的rule。
如果各位想要更详细的了解Easy Rule可以查阅Easy Rule的GitHub网址,和他人对Easy Rule的解释。具体的网址放在下方。
参考文章:
EasyRule – GitHub地址
浅析Easy Rules规则引擎
万物Hello Word
一种技术开始于hello world,为了展示Easy Rule,我们从hello world开始。
1、快速搭建一个maven项目,引入jar。
<!--easy rules核心库-->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>3.3.0</version>
</dependency>
2、自定义一个规则,在规则里注明条件与满足条件需要执行的方法。
package hu.hou.easyrule.rule;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;
@Rule(name = "my_rule", description = "my first try easy rule")
public class MyRule {
@Condition
public boolean myCondition(@Fact("conditionOne") Integer f) {
System.out.println(f);
return f > 1;
}
@Action
public void actionOne(Facts facts) {
for (org.jeasy.rules.api.Fact<?> fact : facts) {
System.out.println(fact);
}
System.out.println("this is first action");
}
@Action
public void actionTwo(Facts facts) {
for (org.jeasy.rules.api.Fact<?> fact : facts) {
System.out.println(fact);
}
System.out.println("this is second action");
}
}
3、有了规则,如何执行呢?这时候就需要一个规则引擎来执行我们自定义的规则。
package hu.hou.easyrule;
import hu.hou.easyrule.rule.MyRule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;
public class Launcher {
public static void main(String[] args) {
// create facts参数
Facts facts = new Facts();
facts.put("conditionOne", 2);
// 规则
Rules rules = new Rules();
rules.register(new MyRule());
// 规则引擎
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.fire(rules, facts);
}
}
至此hello world完成。从上面的例子我们就可以大致看出使用easyRule需要那些东西。让我们看一下最终的运行结果。
尽管粗糙,但是我们正常使用了easy rule,自定义了一个自己的规则。但是我们也可以发现并不是特别的完成,明明是second action却比 first action先执行了,这就是下面要说的问题。
Easy Rule支持很多的配置,如规则的优先级,Action的执行顺序,规则组怎么实现,有条件的规则组怎么实现等等,在Easy Rule的GitHub代码里都有说明,建议可以自行查阅一番。下面的只是个人的一些总结,若有错误,还望指正。
Easy Rule的使用总结
一、规则实现(Rule)
一个规则有三部分组成:规则声明、匹配的条件以及执行的动作。Easy Rule的规则实现形式有多种:1、注解;2、RuleBuilder API;3、文件形式(yaml等)(源码在easy-rules-support项目中)
1、注解
所有的注解都可以自行查看,源码有中有明确的注释。
@Rule注解: 规则的声明,作用于类上,说明是一个规则
name:规则的名称,唯一;
description:描述信息;
priority:优先级。值越小优先级越高。
@Condition注解:规则条件声明,作用于Rule中的一个方法上,返回值为布尔类型。
@Action注解:规则方法注解,当满足一个Rule条件时需要执行的方法,作用于方法。
order:满足条件时有多个方法,方法的执行顺序。值越小越先执行。
@Fact注解:参数注解,可作用于Condition和Rule的方法参数上。
key value的形式
@Priority注解:Rule优先级注解,作用在一个方法上,该方法返回integer类型的值作为rule的优先级。
2、RuleBuilder API
hello world的用例中的rules注册的rule可换成RuleBuilder创建的方式生成一个rule。
Rule rule = new RuleBuilder()
.name("myRule")
.description("myRuleDescription")
.priority(3)
.when(Condition类实例)
.then(Action类实例)
.then(Action类实例)
.build();
3、文件形式
本人并未使用文件形式的配置,请参考文章:轻量级规则引擎easy-rules使用介绍
二、Easy Rule规则组
1、ActivationRuleGroup
代码中注释:激活规则组是触发第一个适用规则并忽略组中其他规则(XOR逻辑)的复合规则。规则首先按其在组中的自然顺序(默认情况下为优先级)排序。
2、ConditionalRuleGroup
代码中注释:条件规则组是一个复合规则,其中具有最高优先级的规则作为一个条件:如果具有最高优先级的规则计算结果为true,则我们尝试计算其余规则并执行计算结果为true的规则。
3、UnitRuleGroup
代码中注释:单元规则组是作为一个单元的复合规则:要么应用所有规则,要么不应用任何规则(全部或无语义)
具体代码参考GitHub项目中的easy-rules-support项目中的测试用例。
三个分组中最重要的是接口Rule中evaluate()
与execute()
方法的实现,可以根据自已的需求自定义这两个方法。
三、Easy Rule实现原理
在学习Easy Rule源码之前需要对 注解
与反射
有一定的了解。
Easy Rule实现的核心代码:
在Hello world实例中的注册rule以及规则引擎的执行具体规则。
待完善!!!
1、注册规则
rules.register(new MyRule());
Rules类中的注册代码:
/**
* Register one or more new rules.
*
* @param rules to register, must not be null
*/
public void register(Object... rules) {
Objects.requireNonNull(rules);
for (Object rule : rules) {
Objects.requireNonNull(rule);
this.rules.add(RuleProxy.asRule(rule));
}
}
其中RuleProxy是一个将使用注解方式的自定义类转为Rule类的一个实现类,具体通过asRule()方法。
/**
* Makes the rule object implement the {@link Rule} interface.
*
* @param rule the annotated rule object.
* @return a proxy that implements the {@link Rule} interface.
*/
public static Rule asRule(final Object rule) {
Rule result;
if (rule instanceof Rule) {
result = (Rule) rule;
} else {
ruleDefinitionValidator.validateRuleDefinition(rule);
result = (Rule) Proxy.newProxyInstance(
Rule.class.getClassLoader(),
new Class[]{Rule.class, Comparable.class},
new RuleProxy(rule));
}
return result;
}