1.简述
Easy Rules是一个简单而强大的Java规则引擎,提供以下功能:
- 轻量级框架和易于学习的API
- 基于POJO的开发与注解的编程模型
- 定义抽象的业务规则并轻松应用它们
- 支持从简单规则创建组合规则的能力
- 支持使用表达式语言(如MVEL和SpEL)定义规则的能力
2.EasyRule的支持环境
EasyRule支持jdk1.7以上的版本。 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>
3.定义规则引擎
| Parameter | Type | Required | Default | content |
|---|---|---|---|---|
| skipOnFirstAppliedRule | boolean | no | MaxInt | 告诉引擎在规则失败时跳过后面的规则 |
| skipOnFirstFailedRule | boolean | no | MaxInt | 告诉引擎一个规则不会被触发跳过后面的规则 |
| skipOnFirstNonTriggeredRule | boolean | no | MaxInt | 告诉引擎一个规则不会被触发跳过后面的规则 |
| rulePriorityThreshold | boolean | no | MaxInt | 告诉引擎如果优先级超过定义的阈值,则跳过下一个规则。版本3.3已经不支持更改,默认MaxInt |
3.1 rulePriorityThreshold
在创建规则引擎时,我们将其属性 rulePriorityThreshold 的值设置为了 1,这样的设置后的效果相当于在定义的所有规则中将 priority > 1 的规则去掉,换种说法就是只考虑 priority的值小于等于 1 的规则。
3.2 skipOnFirstAppliedRule
所有规则按照优先级从高到低的顺序进行判断,当发现一个满足条件的规则并执行了相关操作后,便不再继续判断其他规则
3.3 skipOnFirstNonTriggeredRule
所有规则按照优先级从高到低的顺序进行判断,如果满足当前的规则,则执行相应的操作,直到遇到不满足条件的规则为止,并且也不会对其他规则进行判断了
RulesEngineParameters parameters = new RulesEngineParameters()
.rulePriorityThreshold(10)
.skipOnFirstAppliedRule(true)
.skipOnFirstFailedRule(true)
.skipOnFirstNonTriggeredRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
4.定义规则
4.1 使用rule定义
我们将创建一个始终被触发的规则,在执行时将“hello world”打印到控制台。规则如下:
public class RuleClass {
@Rule(priority = 1)
public static class FizzRule {
@Condition
public boolean isFizz(@Fact("number") Integer number) {
return number % 5 == 0;
}
@Action
public void printFizz() {
System.out.print("fizz");
}
}
@Rule(priority = 2)
public static class BuzzRule {
@Condition
public boolean isBuzz(@Fact("number") Integer number) {
return number % 7 == 0;
}
@Action
public void printBuzz() {
System.out.print("buzz");
}
}
public static class FizzBuzzRule extends UnitRuleGroup {
public FizzBuzzRule(Object... rules) {
for (Object rule : rules) {
addRule(rule);
}
}
@Override
public int getPriority() {
return 0;
}
}
@Rule(priority = 3)
public static 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);
}
}
}
@Condition注解标记计算规则条件的方法。此方法必须是公共的,可以有一个或多个用@Fact注解的参数,并返回布尔类型。只有一个方法能用@Condition注解。
@Action注解标记要执行规则操作的方法。规则可以有多个操作。可以使用order属性按指定的顺序执行操作。默认情况下,操作的顺序为0。
public class RuleClient {
public static void main(String[] args) {
// create a rules engine
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);
// create rules
Rules rules = new Rules();
rules.register(new FizzRule());
rules.register(new BuzzRule());
rules.register(new RuleClass.FizzBuzzRule(new RuleClass.FizzRule(), new RuleClass.BuzzRule()));
rules.register(new NonFizzBuzzRule());
// fire rules
Facts facts = new Facts();
for (int i = 1; i <= 100; i++) {
facts.put("number", i);
fizzBuzzEngine.fire(rules, facts);
System.out.println();
}
}
}
4.2 使用RuleBuilder API定义规则
Rule rule = new RuleBuilder()
.name("myRule")
.description("myRuleDescription")
.priority(3)
.when(condition)
.then(action1)
.then(action2)
.build();
4.3 yml文件定义
规则文件的文件名为 rules.yml ,其内容如下
---
name: "three"
description: "print three"
priority: 0
condition: "number % 3 == 0"
actions:
- "System.out.println("three")"
---
name: "five"
description: "print five"
priority: 1
condition: "number % 5 == 0"
actions:
- "System.out.println("five")"
---
name: "seven"
description: "print seven"
priority: 2
condition: "number % 7 == 0"
actions:
- "System.out.println("seven")"
---
name: "itself"
description: "print the number itself otherwise"
priority: 3
condition: "true"
actions:
- "System.out.println(number)"
客户端调用
public class RuleClient {
public static void main(String[] args) throws FileNotFoundException {
RulesEngine rulesEngine = new DefaultRulesEngine();
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader("rules.yml"));
Facts facts = new Facts();
for (int i = 1; i <= 20; i++) {
System.out.println("====== " + i + " ======");
facts.put("number", i);
rulesEngine.fire(rules, facts);
}
}
}
4.4 MVELRule
public class MVELTestRule {
public static void main(String[] args) {
//规则引擎
// RulesEngine rulesEngine = new DefaultRulesEngine();
DefaultRulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.registerRuleListener(new MyRuleListener());
// ((DefaultRulesEngine) rulesEngine).registerRuleListener(new MyRuleListener());
//规则
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');myResult.setCode('200');myResult.setMsg('success');");
Rules rules = new Rules();
rules.register(ageRule);
Facts facts = new Facts();
User user = new User();
user.setAge(19);
facts.put("user", user);
Map<String, String> map = new HashMap();
MyResult myResult = new MyResult();
facts.put("map", map);
facts.put("myResult", myResult);
rulesEngine.fire(rules, facts);
System.out.println(map);
System.out.println(myResult);
}
}
5.RuleListener
public class MyRuleListener implements RuleListener {
@Override
public boolean beforeEvaluate(Rule rule, Facts facts) {
return true;
}
@Override
public void afterEvaluate(Rule rule, Facts facts, boolean b) {
System.out.println("---MyRuleListener------afterEvaluate-----");
}
@Override
public void beforeExecute(Rule rule, Facts facts) {
System.out.println("---MyRuleListener------beforeExecute-----");
}
@Override
public void onSuccess(Rule rule, Facts facts) {
System.out.println("---MyRuleListener------onSuccess-----");
}
@Override
public void onFailure(Rule rule, Facts facts, Exception e) {
System.out.println("---MyRuleListener------onFailure-----");
}
}
beforeEvaluate该方法在执行@Condition修饰的方法之前执行。该方法返回false则不执行条件的判断,直接跳过该当前rule。afterEvaluate该方法在执行@Condition修饰的方法之后执行。beforeExecute该方法在执行@Action修饰的方法之前执行。onSuccess该方法在执行@Action修饰的方法之后执行。onFailure在执行@Action修饰的方法出现异常时,该方法执行。
在rulesEngine.fire(rules, facts);之前注册规则监听器
((DefaultRulesEngine) rulesEngine).registerRuleListener(new MyRuleListener());
6.RulesEngineListener
public class MyRulesEngineListener implements RulesEngineListener {
@Override
public void beforeEvaluate(Rules rules, Facts facts) {
System.out.println("---MyRulesEngineListener------beforeEvaluate-----");
}
@Override
public void afterExecute(Rules rules, Facts facts) {
System.out.println("---MyRulesEngineListener------afterExecute-----");
}
}
beforeEvaluate该方法在执行@Action修饰的方法之后执行。在RuleListener之前执行afterExecute该方法在执行@Condition修饰的方法之前执行。在RuleListener之后执行
在rulesEngine.fire(rules, facts);之前注册规则引擎监听器
((DefaultRulesEngine) rulesEngine).registerRulesEngineListener(new MyRulesEngineListener());
7.运行规则
// create facts
Facts facts = new Facts();
// create rules
Rules rules = new Rules();
rules.register(new HelloWorldRule());
// create a rules engine and fire rules on known facts
RulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.fire(rules, facts);