国产美女一级毛片精品久久久|婷婷影院在线综合免费视频|最新国产午夜精品视频成人|久久精品九九无码免费

JAVA規(guī)則引擎 -- Drools

來源:長沙北大青鳥大計(jì)校區(qū)|發(fā)布時(shí)間:2015-07-21 14:32:30

 

Drools是一個(gè)基于java的規(guī)則引擎,開源的,可以將復(fù)雜多變的規(guī)則從硬編碼中解放出來,以規(guī)則腳本的形式存放在文件中,使得規(guī)則的變更不需要修正代碼重啟機(jī)器就可以立即在線上環(huán)境生效。


1、Drools語法

 

開始語法之前首先要了解一下drools的基本工作過程,通常而言我們使用一個(gè)接口來做事情,首先要穿進(jìn)去參數(shù),其次要獲取到接口的實(shí)現(xiàn)執(zhí)行完畢后的結(jié)果,而drools也是一樣的,我們需要傳遞進(jìn)去數(shù)據(jù),用于規(guī)則的檢查,調(diào)用外部接口,同時(shí)還可能需要獲取到規(guī)則執(zhí)行完畢后得到的結(jié)果。在drools中,這個(gè)傳遞數(shù)據(jù)進(jìn)去的對(duì)象,術(shù)語叫 Fact對(duì)象。Fact對(duì)象是一個(gè)普通的java bean,規(guī)則中可以對(duì)當(dāng)前的對(duì)象進(jìn)行任何的讀寫操作,調(diào)用該對(duì)象提供的方法,當(dāng)一個(gè)java bean插入到workingMemory中,規(guī)則使用的是原有對(duì)象的引用,規(guī)則通過對(duì)fact對(duì)象的讀寫,實(shí)現(xiàn)對(duì)應(yīng)用數(shù)據(jù)的讀寫,對(duì)于其中的屬性,需要提供getter setter訪問器,規(guī)則中,可以動(dòng)態(tài)的往當(dāng)前workingMemory中插入刪除新的fact對(duì)象。

 

規(guī)則文件可以使用 .drl文件,也可以是xml文件,這里我們使用drl文件。

 

規(guī)則語法:

 

package:對(duì)一個(gè)規(guī)則文件而言,package是必須定義的,必須放在規(guī)則文件第一行。特別的是,package的名字是隨意的,不必必須對(duì)應(yīng)物理路徑,跟java的package的概念不同,這里只是邏輯上的一種區(qū)分。同樣的package下定義的function和query等可以直接使用。

 

比如:package com.drools.demo.point

 

import:導(dǎo)入規(guī)則文件需要使用到的外部變量,這里的使用方法跟java相同,但是不同于java的是,這里的import導(dǎo)入的不僅僅可以是一個(gè)類,也可以是這個(gè)類中的某一個(gè)可訪問的靜態(tài)方法。

 

比如:

 

import com.drools.demo.point.PointDomain;

 

import com.drools.demo.point.PointDomain.getById;

 

rule:定義一個(gè)規(guī)則。rule "ruleName"。一個(gè)規(guī)則可以包含三個(gè)部分:

 

屬性部分:定義當(dāng)前規(guī)則執(zhí)行的一些屬性等,比如是否可被重復(fù)執(zhí)行、過期時(shí)間、生效時(shí)間等。

 

條件部分,即LHS,定義當(dāng)前規(guī)則的條件,如  when Message(); 判斷當(dāng)前workingMemory中是否存在Message對(duì)象。

 

結(jié)果部分,即RHS,這里可以寫普通java代碼,即當(dāng)前規(guī)則條件滿足后執(zhí)行的操作,可以直接調(diào)用Fact對(duì)象的方法來操作應(yīng)用。

 

規(guī)則事例:

 

rule "name"

 

       no-loop true

 

       when

 

               $message:Message(status == 0)

 

       then

 

               System.out.println("fit");

 

               $message.setStatus(1);

 

               update($message);

 

end

 

上述的屬性中:

 

no-loop : 定義當(dāng)前的規(guī)則是否不允許多次循環(huán)執(zhí)行,默認(rèn)是false,也就是當(dāng)前的規(guī)則只要滿足條件,可以無限次執(zhí)行。什么情況下會(huì)出現(xiàn)一條規(guī)則執(zhí)行過一次又被多次重復(fù)執(zhí)行呢?drools提供了一些api,可以對(duì)當(dāng)前傳入workingMemory中的Fact對(duì)象進(jìn)行修改或者個(gè)數(shù)的增減,比如上述的update方法,就是將當(dāng)前的workingMemory中的Message類型的Fact對(duì)象進(jìn)行屬性更新,這種操作會(huì)觸發(fā)規(guī)則的重新匹配執(zhí)行,可以理解為Fact對(duì)象更新了,所以規(guī)則需要重新匹配一遍,那么疑問是之前規(guī)則執(zhí)行過并且修改過的那些Fact對(duì)象的屬性的數(shù)據(jù)會(huì)不會(huì)被重置?結(jié)果是不會(huì),已經(jīng)修改過了就不會(huì)被重置,update之后,之前的修改都會(huì)生效。當(dāng)然對(duì)Fact對(duì)象數(shù)據(jù)的修改并不是一定需要調(diào)用update才可以生效,簡(jiǎn)單的使用set方法設(shè)置就可以完成,這里類似于java的引用調(diào)用,所以何時(shí)使用update是一個(gè)需要仔細(xì)考慮的問題,一旦不慎,極有可能會(huì)造成規(guī)則的死循環(huán)。上述的no-loop true,即設(shè)置當(dāng)前的規(guī)則,只執(zhí)行一次,如果本身的RHS部分有update等觸發(fā)規(guī)則重新執(zhí)行的操作,也不要再次執(zhí)行當(dāng)前規(guī)則。

 

但是其他的規(guī)則會(huì)被重新執(zhí)行,豈不是也會(huì)有可能造成多次重復(fù)執(zhí)行,數(shù)據(jù)紊亂甚至死循環(huán)?答案是使用其他的標(biāo)簽限制,也是可以控制的:lock-on-active true

 

lock-on-active true:通過這個(gè)標(biāo)簽,可以控制當(dāng)前的規(guī)則只會(huì)被執(zhí)行一次,因?yàn)橐粋(gè)規(guī)則的重復(fù)執(zhí)行不一定是本身觸發(fā)的,也可能是其他規(guī)則觸發(fā)的,所以這個(gè)是no-loop的加強(qiáng)版。當(dāng)然該標(biāo)簽正規(guī)的用法會(huì)有其他的標(biāo)簽的配合,后續(xù)提及。

 

date-expires:設(shè)置規(guī)則的過期時(shí)間,默認(rèn)的時(shí)間格式:“日-月-年”,中英文格式相同,但是寫法要用各自對(duì)應(yīng)的語言,比如中文:"29-七月-2010",但是還是推薦使用更為精確和習(xí)慣的格式,這需要手動(dòng)在java代碼中設(shè)置當(dāng)前系統(tǒng)的時(shí)間格式,后續(xù)提及。屬性用法舉例:date-expires "2011-01-31 23:59:59" // 這里我們使用了更為習(xí)慣的時(shí)間格式

 

date-effective:設(shè)置規(guī)則的生效時(shí)間,時(shí)間格式同上。

 

duration:規(guī)則定時(shí),duration 3000   3秒后執(zhí)行規(guī)則

 

salience:優(yōu)先級(jí),數(shù)值越大越先執(zhí)行,這個(gè)可以控制規(guī)則的執(zhí)行順序。

 

 

其他的屬性可以參照相關(guān)的api文檔查看具體用法,此處略。

 

 

 

規(guī)則的條件部分,即LHS部分:

 

when:規(guī)則條件開始。條件可以單個(gè),也可以多個(gè),多個(gè)條件一次排列,比如

 

when

 

         eval(true)

 

         $customer:Customer()

 

         $message:Message(status==0)

 

上述羅列了三個(gè)條件,當(dāng)前規(guī)則只有在這三個(gè)條件都匹配的時(shí)候才會(huì)執(zhí)行RHS部分,三個(gè)條件中第一個(gè)

 

eval(true):是一個(gè)默認(rèn)的api,true 無條件執(zhí)行,類似于 while(true)

 

$message:Message(status==0) 這句話標(biāo)示的:當(dāng)前的workingMemory存在Message類型并且status屬性的值為0的Fact對(duì)象,這個(gè)對(duì)象通常是通過外部java代碼插入或者自己在前面已經(jīng)執(zhí)行的規(guī)則的RHS部分中insert進(jìn)去的。

 

前面的$message代表著當(dāng)前條件的引用變量,在后續(xù)的條件部分和RHS部分中,可以使用當(dāng)前的變量去引用符合條件的FACT對(duì)象,修改屬性或者調(diào)用方法等。可選,如果不需要使用,則可以不寫。

 

條件可以有組合,比如:

 

Message(status==0 || (status > 1 && status <=100))

 

RHS中對(duì)Fact對(duì)象private屬性的操作必須使用getter和setter方法,而RHS中則必須要直接用.的方法去使用,比如

 

  $order:Order(name=="qu")
  $message:Message(status==0 && orders contains $order && $order.name=="qu")

 

特別的是,如果條件全部是 &&關(guān)系,可以使用“,”來替代,但是兩者不能混用

 

如果現(xiàn)在Fact對(duì)象中有一個(gè)List,需要判斷條件,如何判斷呢?

 

看一個(gè)例子:

 

Message {

 

        int status;

 

        List<String> names;

 

}

 

$message:Message(status==0 && names contains "網(wǎng)易" && names.size >= 1)

 

上述的條件中,status必須是0,并且names列表中含有“網(wǎng)易”并且列表長度大于等于1

 

contains:對(duì)比是否包含操作,操作的被包含目標(biāo)可以是一個(gè)復(fù)雜對(duì)象也可以是一個(gè)簡(jiǎn)單的值。

 

Drools提供了十二中類型比較操作符:

 

>  >=  <  <=  ==  !=  contains / not contains / memberOf / not memberOf /matches/ not matches

 

not contains:與contains相反。

 

memberOf:判斷某個(gè)Fact屬性值是否在某個(gè)集合中,與contains不同的是他被比較的對(duì)象是一個(gè)集合,而contains被比較的對(duì)象是單個(gè)值或者對(duì)象。

 

not memberOf:正好相反。

 

matches:正則表達(dá)式匹配,與java不同的是,不用考慮'/'的轉(zhuǎn)義問題

 

 

not matches:正好相反。

 

 

 

規(guī)則的結(jié)果部分

 

當(dāng)規(guī)則條件滿足,則進(jìn)入規(guī)則結(jié)果部分執(zhí)行,結(jié)果部分可以是純java代碼,比如:

 

then

 

       System.out.println("OK"); //會(huì)在控制臺(tái)打印出ok

 

end

 

當(dāng)然也可以調(diào)用Fact的方法,比如  $message.execute();操作數(shù)據(jù)庫等等一切操作。

 

結(jié)果部分也有drools提供的方法:

 

insert:往當(dāng)前workingMemory中插入一個(gè)新的Fact對(duì)象,會(huì)觸發(fā)規(guī)則的再次執(zhí)行,除非使用no-loop限定;

 

update:更新

 

modify:修改,與update語法不同,結(jié)果都是更新操作

 

retract:刪除

 

RHS部分除了調(diào)用Drools提供的api和Fact對(duì)象的方法,也可以調(diào)用規(guī)則文件中定義的方法,方法的定義使用 function 關(guān)鍵字

 

function void console {

 

   System.out.println();

 

   StringUtils.getId();// 調(diào)用外部靜態(tài)方法,StringUtils必須使用import導(dǎo)入,getId()必須是靜態(tài)方法

 

}

 

Drools還有一個(gè)可以定義類的關(guān)鍵字:

 

declare 可以再規(guī)則文件中定義一個(gè)class,使用起來跟普通java對(duì)象相似,你可以在RHS部分中new一個(gè)并且使用getter和setter方法去操作其屬性。

 

declare Address
@author(quzishen) // 元數(shù)據(jù),僅用于描述信息

 

@createTime(2011-1-24)
city : String @maxLengh(100)
postno : int
end

 

上述的'@'是什么呢?是元數(shù)據(jù)定義,用于描述數(shù)據(jù)的數(shù)據(jù)~,沒什么執(zhí)行含義

你可以在RHS部分中使用Address address = new Address()的方法來定義一個(gè)對(duì)象

上一篇:java數(shù)據(jù)庫操作
下一篇:還在遲疑是否選擇學(xué)習(xí)Java?看看這六大優(yōu)勢(shì)

熱門話題

招生熱線: 4008-0731-86 / 0731-82186801

學(xué)校地址: 長沙市天心區(qū)團(tuán)結(jié)路6號(hào)

Copyright © 2006 | 湖南大計(jì)信息科技有限公司 版權(quán)所有

湘ICP備14017520號(hào)-3

關(guān)注我們
在線咨詢
嘿,我來幫您!
陵川县| 南华县| 安达市| 留坝县| 崇礼县| 卓资县| 盐城市| 井研县| 修水县| 集贤县| 兴文县| 环江| 政和县| 明星| 河津市| 广西| 云梦县| 漯河市| 桐梓县| 大石桥市| 泊头市| 东港市| 定边县| 连南| 榆社县| 秦安县| 东丰县| 祁连县| 昂仁县| 济阳县| 尼木县| 屏东市| 神木县| 虞城县| 中阳县| 龙川县| 庄河市| 石柱| 团风县| 京山县| 界首市|