Java-规则引擎easy-rules的使用

规则引擎的目的是以松散灵活的方式来替代硬编码式的if else判断,来达到解耦的目的

easy-rules

easy-rules是个轻量级的规则引擎库,提供了注解等多种配置方式

使用实例

(1)如果一个数字可以被5整除,则输出是5的倍数;
(2)如果一个数字可以被8整除,则输出是8的倍数”;
(3)如果一个数字可以同时被5和8整除,则输出是5的倍数 是8的倍数;
(4)如果一个数字不满足以上三个条件,则输出这个数字本身

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* @Rule可以标注name和description属性,每个rule的name要唯一,如果没有指定,则RuleProxy则默认取类名
* @Condition是条件判断,要求返回boolean值,表示是否满足条件
* @Action标注条件成立之后触发的方法
* @Priority标注该rule的优先级,默认是Integer.MAX_VALUE - 1,值越小越优先
* Created by ChangJie on 2019-10-29.
*/
public class RuleClass {


//同时是5和8的倍数
public static class FiveAndEightMultipleRule extends UnitRuleGroup {

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

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

@Rule(priority = 1)
public static class FiveMultipleRule{

@Condition
public boolean isFiveMultiple(@Fact("number") Integer number){
return number % 5 == 0;
}

@Action
public void print(@Fact("number") Integer number){
System.out.println(number + " is 5 Multiple");
}
}

@Rule(priority = 2)
public static class EightMultipleRule{

@Condition
public boolean isEightMultiple(@Fact("number") Integer number){
return number % 8 == 0;
}

@Action
public void print(@Fact("number") Integer number){
System.out.println(number + " is 8 Multiple");
}
}

@Rule(priority = 3)
public static class NoneFiveAndEightMultipleRule{

@Condition
public boolean isNoneFiveAndEightMultiple(@Fact("number") Integer number){
return number % 5 != 0 && number % 8 != 0;
}

@Action
public void print(@Fact("number") Integer number){
System.out.println(number);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class RuleClient {

public static void main(String[] args) {

// create a rules engine
// 执行规则时,只要有一个规则被触发,则当前被传进来的Fact就不再判断是否满足其他规则的条件
RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);

// create rules
Rules rules = new Rules();
rules.register(new RuleClass.FiveAndEightMultipleRule(new RuleClass.FiveMultipleRule(), new RuleClass.EightMultipleRule()));
rules.register(new RuleClass.FiveMultipleRule());
rules.register(new RuleClass.EightMultipleRule());
rules.register(new RuleClass.NoneFiveAndEightMultipleRule());

// fire rules
Facts facts = new Facts();
for(int i=1; i<=100; i++){
facts.put("number", i);
rulesEngine.fire(rules, facts);
}

}
}

@Rule定义规则,priority设置规则的优先级,@Condition规则触发的条件,@Action标注的方法触发的动作,Facts的用法很像Map,可将其作为参数传入@Condition和@Action标注的方法

原理

可以观察下注册规则时rules的register方法

1
2
3
4
rules.register(new RuleClass.FiveAndEightMultipleRule(new RuleClass.FiveMultipleRule(), new RuleClass.EightMultipleRule()));
rules.register(new RuleClass.FiveMultipleRule());
rules.register(new RuleClass.EightMultipleRule());
rules.register(new RuleClass.NoneFiveAndEightMultipleRule());

其源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void register(Object rule) {
Objects.requireNonNull(rule);
this.rules.add(RuleProxy.asRule(rule));
}

public static Rule asRule(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;
}

可以看到,如果有实现Rule接口,则直接返回,没有的话(即基于注解的形式),则利用JDK的动态代理进行包装
easy-rules还提供了通过配置文件来定义规则,这里不再描述

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×