java規(guī)則引擎easy-rules使用指南 1 - 基本用法

規(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ā)布调卑!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市大咱,隨后出現(xiàn)的幾起案子恬涧,更是在濱河造成了極大的恐慌,老刑警劉巖碴巾,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溯捆,死亡現(xiàn)場離奇詭異,居然都是意外死亡厦瓢,警方通過查閱死者的電腦和手機(jī)提揍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煮仇,“玉大人劳跃,你說我怎么就攤上這事≌愕妫” “怎么了刨仑?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長夹姥。 經(jīng)常有香客問我杉武,道長,這世上最難降的妖魔是什么佃声? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任艺智,我火速辦了婚禮,結(jié)果婚禮上圾亏,老公的妹妹穿的比我還像新娘十拣。我一直安慰自己,他們只是感情好志鹃,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布夭问。 她就那樣靜靜地躺著,像睡著了一般曹铃。 火紅的嫁衣襯著肌膚如雪缰趋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音秘血,去河邊找鬼味抖。 笑死,一個胖子當(dāng)著我的面吹牛灰粮,可吹牛的內(nèi)容都是我干的仔涩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼粘舟,長吁一口氣:“原來是場噩夢啊……” “哼熔脂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柑肴,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤霞揉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后晰骑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體适秩,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年些侍,在試婚紗的時候發(fā)現(xiàn)自己被綠了隶症。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡岗宣,死狀恐怖蚂会,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耗式,我是刑警寧澤胁住,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站刊咳,受9級特大地震影響彪见,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娱挨,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一余指、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跷坝,春花似錦酵镜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贴届,卻和暖如春靠粪,著一層夾襖步出監(jiān)牢的瞬間蜡吧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工占键, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留昔善,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓捞慌,卻偏偏與公主長得像耀鸦,于是被迫代替她去往敵國和親柬批。 傳聞我的和親對象是個殘疾皇子啸澡,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容