從今天開始,我們將分兩期來詳細的介紹Drools規則引擎的原理,和各關鍵類的使用方法。
Drools
規則引擎(上)
1. 概述
:
Drools
分為兩個主要部分:構建(
Authoring
)和運行時(
Runtime
)。
構建的過程涉及到
.drl
或
.xml
規則文件的創建,它們被讀入一個解析器,使用
ANTLR 3
語法進行解析。解析器對語法進行正確性的檢查,然后產生一種中間結構“
descr
”,
descr
用
AST
來描述規則。
AST
然后被傳到
PackageBuilder
,由
PackagBuilder
來產生
Packaged
對象。
PackageBuilder
還承擔著一些代碼產生和編譯的工作,這些對于產生
Package
對象都時必需的。
Package
對象是一個可以配置的,可序列化的,由一個或多個規則組成的對象。下圖闡明了上述過程:
?

Figure 1.1 Authoring Components
RuleBase
是一個運行時組件,它包含了一個或多個
Package
對象。可以在任何時刻將一個
Package
對象加入或移出
RuleBase
對象。一個
RuleBase
對象可以在任意時刻實例化一個或多個
WorkingMemory
對象,在它的內部保持對這些
WorkingMemory
的弱引用。
WorkingMemory
由一系列子組件組成。當應用程序中的對象被
assert
進
WorkingMemory
,可能會導致一個或多個
Activation
的產生,然后由
Agenda
負責安排這些
Activation
的執行。下圖說明了上述過程:
?

Figure 1.2 .?Runtime Components
2.構建(Authoring):
主要有三個類用來完成構建過程:DrlParser, XmlParser 和 PackageBuilder。兩個解析器類從傳入的Reader實例產生descr AST模型。PackageBuilder提供了簡便的API,使你可以忽略那兩個類的存在。這兩個簡單的方法是:“addPackageFromDrl”和“addPackageFromXml”,兩個都只要傳入一個Reader實例作為參數。下面的例子說明了如何從classpath中的xml和drl文件創建一個Package對象。注意:所有傳入同一個PackageBuilder實例的規則源,都必須是在相同的package 命名空間(namespace)中。
PackageBuilder?builder?=?new?PackageBuilder();
builder.addPackageFromDrl(?new?InputStreamReader(?getClass().getResourceAsStream(?"package1.drl"?)?)?);
builder.addPackageFromXml(?new?InputStreamReader(?getClass().getResourceAsStream(?"package2.drl"?)?)?);
Package?pkg?=?builder.getPackage();

Figure 2.1 PackageBuilder
PackageBuilder是可以配置的,使用PackageBuilderConfiguration。通常,你可以指定另一個parent ClassLoader和用什么編譯器(compiler),默認是Eclipse JDT。下面顯示了如何指定JANINO編譯器:
PackageBuilderConfiguration?conf?=?new?PackageBuilderConfiguration();
conf.setCompiler(?PackageBuilderConfiguration.JANINO?);
PackageBuilder?builder?=?new?PackageBuilder(?conf?);
Figure 2.2 .?PackageBuilderConfiguration
3.RuleBase:

Figure 3.1 .?RuleBase
一個RuleBase包含了多個將被使用的規則包(packages of rules)。一個RuleBase是可以序列化的,所以它可以被配置到JNDI或其他類似的服務。通常,第一次使用時,一個RuleBase被創建并緩存。RuleBase用RuleBaseFactory來實例化,默認返回一個ReteOO RuleBase。可以傳入參數來指定采用ReteOO或Leaps。然后,用addPackage方法加入Package實例。你可以加入有相同命名空間(namespace)的多個Package。
RuleBase?ruleBase??=?RuleBaseFactory.newRuleBase();
ruleBase.addPackage(pkg);
Figure 3.2. RuleBaseFactory
一個
rulebase
instance
是線程安全的,所有你可以在你的應用中,讓一個
rulebase instance
在多個線程中共享。對于一個
rulebase
的最通常的操作是產生一個新的
WorkingMemory
。
這個
rulebase
保持著到它所產生的
WorkingMemoryd
的弱引用,所以在長時間運行的
WorkingMemory
中,如果
rules
發生改變,這些
WorkingMemory
可以即使的根據最新的
rules
進行更新,而不必重啟
WorkingMemory
。你也可以指定
RuleBase
不必保持一個弱引用,但是你要保證
RuleBase
不用更新。
ruleBase.newWorkingMemory();??
//
?maintains?a?weak?reference.
ruleBase.newWorkingMemory(?
false
?);?
//
?do?not?maintain?a?weak?reference
任何時候,
Package
可以被加入或移除;所有的改變都會被反映到現存的
WorkingMemory
中。不要忘了調用
fireAllRules()
讓
Activations
激發。
ruleBase.addPackage(?pkg??);??
//
?Add?a?package?instance
ruleBase.removePackage(?
"
org.com.sample
"
??);??
//
?remove?a?package,?and?all?its?parts,
by?it's?namespace
ruleBase.removeRule(?
"
org.com.sample
"
,?
"
my?rule
"
?);?
//
?remove?a?specific?rule?from?a
namespace
雖然有刪除一個單獨規則的方法,但是卻沒有加入一個單獨規則的方法(要達到這個目的只有加入一個只有一條規則的
package
)。
RuleBaseConfigurator
可以指定
RuleBase
的附加行為。在加入
RuleBase
后,
RuleBaseConfiguration
就變成不可變對象。
RuleBaseConfiguration?conf?
=
?
new
?RuleBaseConfiguration();
conf.setProperty(?RuleBaseConfiguration.PROPERTY_ASSERT_BEHAVIOR,
??????????????????RuleBaseConfiguration.WM_BEHAVIOR_EQUALITY?);
RuleBase?ruleBase?
=
?
new
?ReteooRuleBase(?conf?);
兩個主要的屬性是:
PROPERT_ASSERT_BEHAVIOR
和
PROPERTY_LOGICAL_OVERRIDE_BEHAVIOR
(在以后的部分中會解釋)。所有的屬性值都是
RuleBaseConfiguration
類中的靜態域常量。
Figure 3.3 RuleBaseConfiguration