3、規(guī)則引擎的工作機制
下面專門研究規(guī)則引擎的內(nèi)部處理過程。如圖3所示,規(guī)則引擎從隊列管理器中依次接收信息元,然后依規(guī)則的定義順序檢查信息元所帶規(guī)則集中的規(guī)則。如圖所示,規(guī)則引擎檢查第一個規(guī)則并對其條件過濾器求值,如果值為假,所有與此規(guī)則相關(guān)的動作皆被忽略并繼續(xù)執(zhí)行下一條規(guī)則。如果第二條規(guī)則的過濾器值為真,所有與此規(guī)則相關(guān)的動作皆依定義順序執(zhí)行,執(zhí)行完畢繼續(xù)下一條規(guī)則。該信息元中的所有規(guī)則執(zhí)行完畢后,信息元將被銷毀,然后從隊列管理器接收下一個信息元。在這個過程中并未考慮兩個特殊動作:放棄動作(Discard Action)和包含動作(Include Action)。放棄動作如果被執(zhí)行,將會跳過其所在信息元中接下來的所有規(guī)則,并銷毀所在信息元,規(guī)則引擎繼續(xù)接收隊列管理器中的下一個信息元。包含動作其實就是動作中包含其它現(xiàn)存規(guī)則集的動作。包含動作如果被執(zhí)行,規(guī)則引擎將暫停并進入被包含的規(guī)則集,執(zhí)行完畢后,規(guī)則引擎還會返回原來暫停的地方繼續(xù)執(zhí)行。這一過程將遞歸進行。
Java規(guī)則引擎的工作機制與上述規(guī)則引擎機制十分類似,只不過對上述概念進行了重新包裝組合。Java規(guī)則引擎對提交給引擎的Java數(shù)據(jù)對象進行檢索,根據(jù)這些對象的當前屬性值和它們之間的關(guān)系,從加載到引擎的規(guī)則集中發(fā)現(xiàn)符合條件的規(guī)則,創(chuàng)建這些規(guī)則的執(zhí)行實例。這些實例將在引擎接到執(zhí)行指令時、依照某種優(yōu)先序依次執(zhí)行。一般來講,Java規(guī)則引擎內(nèi)部由下面幾個部分構(gòu)成:工作內(nèi)存(Working Memory)即工作區(qū),用于存放被引擎引用的數(shù)據(jù)對象集合;規(guī)則執(zhí)行隊列,用于存放被激活的規(guī)則執(zhí)行實例;靜態(tài)規(guī)則區(qū),用于存放所有被加載的業(yè)務規(guī)則,這些規(guī)則將按照某種數(shù)據(jù)結(jié)構(gòu)組織,當工作區(qū)中的數(shù)據(jù)發(fā)生改變后,引擎需要迅速根據(jù)工作區(qū)中的對象現(xiàn)狀,調(diào)整規(guī)則執(zhí)行隊列中的規(guī)則執(zhí)行實例。Java規(guī)則引擎的結(jié)構(gòu)示意圖如圖4所示。
當引擎執(zhí)行時,會根據(jù)規(guī)則執(zhí)行隊列中的優(yōu)先順序逐條執(zhí)行規(guī)則執(zhí)行實例,由于規(guī)則的執(zhí)行部分可能會改變工作區(qū)的數(shù)據(jù)對象,從而會使隊列中的某些規(guī)則執(zhí)行實例因為條件改變而失效,必須從隊列中撤銷,也可能會激活原來不滿足條件的規(guī)則,生成新的規(guī)則執(zhí)行實例進入隊列。于是就產(chǎn)生了一種“動態(tài)”的規(guī)則執(zhí)行鏈,形成規(guī)則的推理機制。這種規(guī)則的“鏈式”反應完全是由工作區(qū)中的數(shù)據(jù)驅(qū)動的。
任何一個規(guī)則引擎都需要很好地解決規(guī)則的推理機制和規(guī)則條件匹配的效率問題。規(guī)則條件匹配的效率決定了引擎的性能,引擎需要迅速測試工作區(qū)中的數(shù)據(jù)對象,從加載的規(guī)則集中發(fā)現(xiàn)符合條件的規(guī)則,生成規(guī)則執(zhí)行實例。1982年美國卡耐基·梅隆大學的Charles L. Forgy發(fā)明了一種叫Rete算法,很好地解決了這方面的問題。目前世界頂尖的商用業(yè)務規(guī)則引擎產(chǎn)品基本上都使用Rete算法。
Java規(guī)則引擎API——JSR-94
為了使規(guī)則引擎技術(shù)標準化,Java社區(qū)制定了Java規(guī)則引擎API(JSR94)規(guī)范。它為Java平臺訪問規(guī)則引擎定義了一些簡單的API。
Java規(guī)則引擎API在javax.rules包中定義,是訪問規(guī)則引擎的標準企業(yè)級API。Java規(guī)則引擎API允許客戶程序使用統(tǒng)一的方式和不同廠商的規(guī)則引擎產(chǎn)品交互,就如同使用JDBC編寫獨立于廠商訪問不同的數(shù)據(jù)庫產(chǎn)品一樣。Java規(guī)則引擎API包括創(chuàng)建和管理規(guī)則集合的機制,在工作區(qū)中添加,刪除和修改對象的機制,以及初始化,重置和執(zhí)行規(guī)則引擎的機制。
1、Java規(guī)則引擎API體系結(jié)構(gòu)
Java規(guī)則引擎API主要由兩大類API組成: 規(guī)則管理API(The Rules Administrator API)和運行時客戶API(The Runtime Client API)。
1)規(guī)則管理API
規(guī)則管理API在javax.rules.admin中定義,包含裝載規(guī)則以及與規(guī)則對應的動作(執(zhí)行集 execution sets)以及實例化規(guī)則引擎。規(guī)則可以從外部資源中裝載,比如URI,Input streams, XML streams和readers等等。同時規(guī)則管理API還提供了注冊和取消注冊執(zhí)行集以及對執(zhí)行集進行維護的機制。使用admin包定義規(guī)則有助于對客戶訪問運行規(guī)則進行控制管理,它通過在執(zhí)行集上定義許可權(quán)使得未經(jīng)授權(quán)的用戶無法訪問受控規(guī)則。
規(guī)則管理API使用類RuleServiceProvider來獲得規(guī)則管理器(RuleAdministrator)接口的實例。該接口提供方法注冊和取消注冊執(zhí)行集。規(guī)則管理器提供了本地和遠程的RuleExecutionSetProvider,它負責創(chuàng)建規(guī)則執(zhí)行集(RuleExecutionSet)。規(guī)則執(zhí)行集可以從如XML streams, binary streams等來源中創(chuàng)建。這些數(shù)據(jù)來源及其內(nèi)容經(jīng)匯集和序列化后傳送到遠程的運行規(guī)則引擎的服務器上。在大多數(shù)應用程序中,遠程規(guī)則引擎或遠程規(guī)則數(shù)據(jù)來源的情況并不多。為了避免這些情況中的網(wǎng)絡(luò)開銷,API規(guī)定了可以從運行在同一JVM中規(guī)則庫中讀取數(shù)據(jù)的本地RuleExecutionSetProvider。規(guī)則執(zhí)行集接口除了擁有能夠獲得有關(guān)規(guī)則執(zhí)行集的方法,還有能夠檢索在規(guī)則執(zhí)行集中定義的所有規(guī)則對象。這使得客戶能夠知道規(guī)則集中的規(guī)則對象并且按照自己需要來使用它們。
2)運行時客戶API
運行時API在javax.rules包中定義,為規(guī)則引擎用戶運行規(guī)則獲得結(jié)果提供了類和方法。運行時客戶只能訪問那些使用規(guī)則管理API注冊過的規(guī)則,運行時API幫助用戶獲得規(guī)則會話,并在這個會話中執(zhí)行規(guī)則。
運行時API提供了對廠商規(guī)則引擎API的訪問方法,這類似于JDBC。類RuleServiceProvider提供了對具體規(guī)則引擎實現(xiàn)的運行時和管理API的訪問,規(guī)則引擎廠商通過該類將其規(guī)則引擎實現(xiàn)提供給客戶,并獲得RuleServiceProvider唯一標識規(guī)則引擎的URL。此URL的標準用法是使用類似于“com.mycompany.myrulesengine.rules.RuleServiceProvider”這樣的Internet域名空間,這保證了訪問URL的唯一性。類RuleServiceProvider內(nèi)部實現(xiàn)了規(guī)則管理和運行時訪問所需的接口。所有的RuleServiceProvider要想被客戶所訪問都必須用RuleServiceProviderManager進行注冊,注冊方式類似于JDBC API的DriverManager和Driver。
運行時接口是運行時API的關(guān)鍵部分。運行時接口提供了用于創(chuàng)建規(guī)則會話(RuleSession)的方法,規(guī)則會話是用來運行規(guī)則的。運行時API同時也提供了訪問在service provider注冊過的所有規(guī)則執(zhí)行集(RuleExecutionSets)。規(guī)則會話接口定義了客戶使用的會話的類型,客戶根據(jù)自己運行規(guī)則的方式可以選擇使用有狀態(tài)會話或者無狀態(tài)會話。無狀態(tài)會話的工作方式就像一個無狀態(tài)會話bean?蛻艨梢园l(fā)送單個輸入對象或一列對象來獲得輸出對象。當客戶需要一個與規(guī)則引擎間的專用會話時,有狀態(tài)會話就很有用。輸入的對象通過addObject()方法可以加入到會話當中。同一個會話當中可以加入多個對象。對話中已有對象可以通過使用updateObject()方法得到更新。只要客戶與規(guī)則引擎間的會話依然存在,會話中的對象就不會丟失。
RuleExecutionSetMetaData接口提供給客戶讓其查找規(guī)則執(zhí)行集的元數(shù)據(jù)(metadata)。元數(shù)據(jù)通過規(guī)則會話接口(RuleSession Interface)提供給用戶。
2、Java規(guī)則引擎API安全問題
規(guī)則引擎API將管理API和運行時API加以分開,從而為這些包提供了較好粒度的安全控制。規(guī)則引擎API并沒有提供明顯的安全機制,它可以和J2EE規(guī)范中定義的標準安全API聯(lián)合使用。安全可以由以下機制提供,如Java 認證和授權(quán)服務 (JAAS),Java加密擴展(JCE),Java安全套接字擴展(JSSE),或者其它定制的安全API。使用JAAS可以定義規(guī)則執(zhí)行集的許可權(quán)限,從而只有授權(quán)用戶才能訪問。
3、異常與日志
規(guī)則引擎API定義了javax.rules.RuleException作為規(guī)則引擎異常層次的根類。所有其它異常都繼承于這個根類。規(guī)則引擎中定義的異常都是受控制的異常(checked exceptions),所以捕獲異常的任務就交給了規(guī)則引擎。規(guī)則引擎API沒有提供明確的日志機制,但是它建議將Java Logging API用于規(guī)則引擎API。
JSR 94 為規(guī)則引擎提供了公用標準API,僅僅為實現(xiàn)規(guī)則管理API和運行時API提供了指導規(guī)范,并沒有提供規(guī)則和動作該如何定義以及該用什么語言定義規(guī)則,也沒有為規(guī)則引擎如何讀和評價規(guī)則提供技術(shù)性指導。
相關(guān)推薦:計算機等考二級JAVA基礎(chǔ)知識:Java異常集北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |