接触过Drools的同学都会被复杂的Api给难住,简直就是入门到放弃的一个过程,而EasyRule就是Drools的简化版,裁剪了部分使用场景非常少的复杂功能,也简化了很多Drools中的组件,这样我们在使用EasyRule的时候对于API理解就非常容易了
什么是Easy Rules?
Easy Rules是一个简单的JAVA开源规则引擎,它提供了规则抽象来创建带有评估条件和执行操作的规则,规则引擎API通过运行一组规则以评估条件和执行操作。
框架特点
- 轻量级类库
- 容易学习的API
- 基于POJO的注解编程模型开发
- 通过高效的抽象来定义业务规则并易于用JAVA应用它们
- 支持通过原始规则创建复合规则
- 支持用表达式语言定义规则
功能组件
- 事实(Fact):业务数据,结构类似HashMap;
- 规则(Rule):业务规则,包含条件评估、动作执行,条件评估结果为true,则执行对应动作;
- 规则引擎(Rule Engine):以指定的方式执行规则;
- 规则监听(Rule Listener):监听规则的执行情况;
- 规则引擎监听(Rule Engine Listener):监听规则引擎的执行情况;
事例
定义规则
注解方式定义规则:
@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!");
}
}
流式编程方式定义规则:
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();
表达式方式定义规则:
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文件方式定义规则:
name: "weather rule"
description: "if it rains then take an umbrella"
condition: "rain == true"
actions:
- "System.out.println(\"It rains, take an umbrella!\");"
Rule weatherRule = MVELRuleFactory.createRuleFrom(new File("weather-rule.yml"));
执行规则:
public class Test {
public static void main(String[] args) {
// define facts
Facts facts = new Facts();
facts.put("rain", true);
// define rules
Rule weatherRule = ...
Rules rules = new Rules();
rules.register(weatherRule);
// fire rules on known facts
RulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.fire(rules, facts);
}
}
具体场景事例
场景说明:
假设我们有这样一个场景:
- 如果一个数字可以被5整除,则输出“fizz”;
- 如果一个数字可以被7整除,则输出“buzz”;
- 如果一个数字可以同时被5和7整除,则输出“fizzbuzz”;
- 如果一个数字不满足以上三个条件,则输出这个数字本身。
不使用规则引擎实现:
public class FizzBuzzMain {
public static void main(String[] args) {
for(int i = 1; i <= 100; i++) {
if (((i % 5) == 0) && ((i % 7) == 0))
System.out.print("fizzbuzz");
else if ((i % 5) == 0) System.out.print("fizz");
else if ((i % 7) == 0) System.out.print("buzz");
else System.out.print(i);
System.out.println();
}
System.out.println();
}
}
使用Easy Rules实现:
1. 引入依赖
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-support</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>3.2.0</version>
</dependency>
2. 使用注解方式定义规则:
2.1 定义规则:
public class RuleClass {
@Rule(priority = 1)
public static class FizzRule {
@Condition
public boolean isFizz(@Fact("number") int 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") int 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") int number) {
return number % 5 != 0 || number % 7 != 0;
}
@Action
public void printInput(@Fact("number") int number) {
System.out.print(number);
}
}
}
2.2 客户端调用:
public class FizzBuzzMainWithRule {
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 FizzBuzzRule(new FizzRule(), new 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();
}
}
}
3. 使用yml文件定义规则:
3.1 定义规则:
---
name: "fizz rule"
description: "print fizz if the number is multiple of 5"
priority: 1
condition: "number % 5 == 0"
actions:
- "System.out.println(\"fizz\")"
---
name: "buzz rule"
description: "print buzz if the number is multiple of 7"
priority: 2
condition: "number % 7 == 0"
actions:
- "System.out.println(\"buzz\")"
---
name: "fizzbuzz rule"
description: "print fizzbuzz if the number is multiple of 5 and 7"
priority: 0
condition: "number % 5 == 0 && number % 7 == 0"
actions:
- "System.out.println(\"fizzbuzz\")"
---
name: "non fizzbuzz rule"
description: "print the number itself otherwise"
priority: 3
condition: "number % 5 != 0 || number % 7 != 0"
actions:
- "System.out.println(number)"
3.2 客户端调用:
public class FizzBuzzMainWithYmlRule {
public static void main(String[] args) throws FileNotFoundException {
// create a rules engine
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters);
// create rules
String filePath = System.getProperty("user.dir") + "/src/main/resources/easyrules/fizzbuzz/rule.yml";
Rules rules = MVELRuleFactory.createRulesFrom(new FileReader(filePath));
// fire rules
Facts facts = new Facts();
for (int i = 1; i <= 100; i++) {
facts.put("number", i);
fizzBuzzEngine.fire(rules, facts);
System.out.println();
}
}
}
更多事例
- Easy Rules官方wiki
参考
- Easy Rules官方文档