規(guī)則引擎能干什么
規(guī)則引擎的工作方式有點像if-else,它允許你設(shè)置一些條件和動作,然后在程序運(yùn)行時判斷某些動作該不該執(zhí)行繁成。
easy-rules是一款輕量級的java規(guī)則引擎,目前它的長期支持版本是4.1.x,所以我們就以4.1.0版本來看一下如何使用衷笋。
如何引入
如果使用maven,可以直接在pom中加入:
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>4.1.0</version>
</dependency>
如果需要對MVEL, SpEL和JEXL表達(dá)式的支持矩屁,還需要引入相應(yīng)的支持包:
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-spel</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-jexl</artifactId>
<version>4.1.0</version>
</dependency>
一個簡單的例子
使用easy-rules非常簡單辟宗,只需要兩個步驟:
- 創(chuàng)建規(guī)則和動作
- 運(yùn)行引擎
以下是一個簡單的例子:
public class Test {
public static void main(String[] args) {
// define rules
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();
Rules rules = new Rules();
rules.register(weatherRule);
// define facts
Facts facts = new Facts();
facts.put("rain", true);
// fire rules on known facts
RulesEngine rulesEngine = new DefaultRulesEngine();
rulesEngine.fire(rules, facts);
}
}
例子中的weatherRule是構(gòu)建的條件和動作爵赵,其中“when”里面的是條件,“then”里面的是滿足條件后需要執(zhí)行的動作泊脐。
facts是運(yùn)行中實際的數(shù)據(jù)空幻。
這個例子會在控制臺打印出:It rains, take an umbrella!
如何使用Rule
1 介紹
Rule用于定義規(guī)則和行為,它可以設(shè)置以下這些屬性:
- name: 命名空間中的唯一規(guī)則名稱
- description: 描述
- priority: 優(yōu)先級
- when:規(guī)則
- then:行為
當(dāng)when中的表達(dá)式返回true時容客,將執(zhí)行then中的表達(dá)式秕铛。
then里面除了可以執(zhí)行方法外,也可以修改Facts里面的數(shù)據(jù)耘柱。
2 Rule的多種寫法
easy-rules提供了多種定義Rule的寫法如捅,還是以上面的例子舉例,下面的Rule寫法與上面例子中的寫法是等價的调煎。
2.1 使用RuleBuilder
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();
2.2 使用注解
@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!");
}
}
2.3 使用表達(dá)式語言
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!\");");
使用表達(dá)式語言需要引入對應(yīng)的支持包镜遣,比如這里使用了MVEL,那么需要在pom中引入easy-rules-mvel這個包
2.4 使用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"));
3 復(fù)合規(guī)則
有時候我們需要把多個規(guī)則放在一起使用士袄,就好像寫多層if-else一樣悲关。
easy-rules為此提供了三個對象來支持復(fù)合規(guī)則的使用:
- UnitRuleGroup:要么應(yīng)用所有rule,要么不應(yīng)用任何rule娄柳。
- ActivationRuleGroup:它觸發(fā)第一個適用的rule并忽略組中的其他rule(XOR 邏輯)寓辱。rule首先按其在組內(nèi)的自然順序排序,如果設(shè)置了priority赤拒,那么數(shù)字越小的優(yōu)先級越高秫筏。
- ConditionalRuleGroup::只有具有最高優(yōu)先級的rule評估為真,才觸發(fā)其余rule挎挖。
下面是使用示范:
//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);
如何使用facts
Fact是用來裝需要判斷的數(shù)據(jù)的这敬,它的API定義如下:
public class Fact<T> {
private final String name;
private final T value;
}
使用的時候直接用Facts,就跟Map用法差不多:
Facts facts = new Facts();
facts.put("foo", "bar");
Rule的“then”代碼中可以修改facts的數(shù)據(jù)蕉朵,可以使用這個特性來獲取返回值崔涂。
例如:
Rule ageRule = new MVELRule()
.name("age rule")
.description("Check if person's age is > 18 and marks the person as adult")
.priority(1)
.when("person.age > 18")
.then("person.setAdult(true);");
注意:
- 如果when方法中缺少注入的Fact,引擎將記錄一個警告并認(rèn)為條件評估為false始衅。
- 如果then方法中缺少注入的Rule冷蚂,則不會執(zhí)行該操作,并且引擎將拋出一個org.jeasy.rules.core.NoSuchFactException.
如何使用Engine
1 Engine的兩種實現(xiàn)
Easy Rules 提供了兩種RulesEngine接口實現(xiàn):
DefaultRulesEngine:根據(jù)其自然順序應(yīng)用規(guī)則(默認(rèn)為優(yōu)先級)汛闸。
InferenceRulesEngine:不斷地對已知事實應(yīng)用規(guī)則蝙茶,直到不再適用規(guī)則為止。
DefaultRulesEngine的作用很好理解蛉拙,就像上面那些例子表現(xiàn)出來的一樣尸闸。
InferenceRulesEngine則相當(dāng)于在DefaultRulesEngine的基礎(chǔ)上加了一個循環(huán)。還是以開頭的代碼舉例孕锄,換成InferenceRulesEngine吮廉。
這時控制臺將重復(fù)打印“It rains, take an umbrella!”。
public class Test {
public static void main(String[] args) {
// define rules
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();
Rules rules = new Rules();
rules.register(weatherRule);
// define facts
Facts facts = new Facts();
facts.put("rain", true);
// fire rules on known facts
RulesEngine rulesEngine = new InferenceRulesEngine();
rulesEngine.fire(rules, facts);
}
}
2 Engine的配置參數(shù)
Engine支持以下幾個參數(shù)配置:
范圍 | 類型 | 必需的 | 默認(rèn) |
---|---|---|---|
rulePriorityThreshold | int | no | MaxInt |
skipOnFirstAppliedRule | boolean | no | false |
skipOnFirstFailedRule | boolean | no | false |
skipOnFirstNonTriggeredRule | boolean | no | false |
- skipOnFirstAppliedRule:在應(yīng)用規(guī)則時跳過下一個規(guī)則途事。
- skipOnFirstFailedRule:在規(guī)則失敗時跳過下一個規(guī)則共螺。
- skipOnFirstNonTriggeredRule:在未觸發(fā)規(guī)則時跳過下一個規(guī)則萍虽。
- rulePriorityThreshold:priority 大于rulePriorityThreshold時跳過下一個規(guī)則。
寫法如下:
RulesEngineParameters parameters = new RulesEngineParameters()
.rulePriorityThreshold(10)
.skipOnFirstAppliedRule(true)
.skipOnFirstFailedRule(true)
.skipOnFirstNonTriggeredRule(true);
RulesEngine rulesEngine = new DefaultRulesEngine(parameters);
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布调卑!