Java規則引擎與其API(JSR-94)

複雜企業級項目的開發以及其中隨外部條件 不斷變化的業務規則(business logic),迫切須要分離商業決策者的商業決策邏輯和應用開發者的技術決策,並把這些商業決策放在中心數據庫或其餘統一的地方,讓它們能在運行時(即商 務時間)能夠動態地管理和修改從而提供軟件系統的柔性和適應性。規則引擎正是應用於上述動態環境中的一種解決方法。 html

本文第一部分簡要介紹了 規則引擎的產生背景和基於規則的專家系統,第二部分介紹了什麼是規則引擎及其架構和算法,第三部分介紹了商業產品和開源項目實現等各類Java規則引擎, 第四部分對Java規則引擎API(JSR-94)做了詳細介紹,講解了其體系結構,管理API和運行時API及相關安全問題,第五部分則對規則語言及其 標準化做了探討,第六部分給出了一個使用Java規則引擎API的簡單示例,第七部分給予小結和展望。 java

一、 介紹

1.1 規則引擎產生背景

企 業管理者對企業級IT系統的開發有着以下的要求:(1)爲提升效率,管理流程必須自動化,即便現代商業規則異常複雜(2)市場要求業務規則常常變化,IT 系統必須依據業務規則的變化快速、低成本的更新(3)爲了快速、低成本的更新,業務人員應能直接管理IT系統中的規則,不須要程序開發人員參與。 程序員

而 項目開發人員則碰到了如下問題:(1)程序=算法+數據結構,有些複雜的商業規則很難推導出算法和抽象出數據模型(2)軟件工程要求從需求->設計 ->編碼,然而業務規則經常在需求階段可能尚未明確,在設計和編碼後還在變化,業務規則每每嵌在系統各處代碼中(3)對程序員來講,系統已經維 護、更新困難,更不可能讓業務人員來管理。 算法

基於規則的專家系統的出現給開發人員以解決問題的契機。規則引擎由基於規則的專家系統中的推理引擎發展而來。下面簡要介紹一下基於規則的專家系統。 數據庫

1.2 基於規則的專家系統(RBES)

專家系統是人工智能的一個分支,它模仿人類的推理方式,使用試探性的方法進行推理,並使用人類能理解的術語解釋和證實它的推理結論。專家系統有不少分類:神經網絡、基於案例推理和基於規則系統等。 編程

RBES包括三部分:Rule Base(knowledge base)、Working Memory(fact base)和Inference Engine(推理引擎)。它們的結構以下所示: api

圖1.基於規則的專家系統組成
圖1.基於規則的專家系統組成

如 上圖所示,推理引擎包括三部分:Pattern Matcher、Agenda和Execution Engine。Pattern Matcher什麼時候執行哪一個規則;Agenda管理PatternMatcher挑選出來的規則的執行次序;Execution Engine負責執行規則和其餘動做。 安全

推理引擎經過決定哪些規則知足事實或目標,並授予規則優先級,知足事實或目標的規則被加入議程。 存在二者推理方式:演繹法(Forward-Chaining正向鏈)和概括法(Backward-Chaining反向鏈)。演繹法從一個初始的事實出發,不斷地應用規則得出結論(或執行指定的動做)。而概括法則是從假設出發,不斷地尋找符合假設的事實。 服務器

回頁首 網絡

二、 規則引擎

2.1 業務規則

一 個業務規則包含一組條件和在此條件下執行的操做,它們表示業務規則應用程序的一段業務邏輯。業務規則一般應該由業務分析人員和策略管理者開發和修改,但有 些複雜的業務規則也能夠由技術人員使用面嚮對象的技術語言或腳原本定製。業務規則的理論基礎是:設置一個或多個條件,當知足這些條件時會觸發一個或多個操 做。

2.2 規則引擎

什麼是規則引擎?規則引擎是如何執行規則的?這能夠稱之爲"什麼"與"如 何"的問題。到底規則引擎是什麼仍是目前業界一個比較有爭議的問題,在JSR-94種也幾乎沒有定義。能夠這樣認爲充分定義和解決了"如何"的問題,"什 麼"問題本質上也迎刃而解。也許這又是一種"先有蛋仍是先有雞"哲學爭論。從此標準規則語言的定義和推出及相關標準的制定應該能夠給這樣的問題和爭論劃上 一個句號。本文中,暫且這樣述說什麼是規則引擎:規則引擎由推理引擎發展而來,是一種嵌入在應用程序中的組件,實現了將業務決策從應用程序代碼中分離出 來,並使用預約義的語義模塊編寫業務決策。接受數據輸入,解釋業務規則,並根據規則作出業務決策。

2.3 規則引擎的使用方式

由 於規則引擎是軟件組件,因此只有開發人員纔可以經過程序接口的方式來使用和控制它,規則引擎的程序接口至少包含如下幾種API:加載和卸載規則集的 API;數據操做的API;引擎執行的API。開發人員在程序中使用規則引擎基本遵循如下5個典型的步驟:建立規則引擎對象;向引擎中加載規則集或更換規 則集;向引擎提交須要被規則集處理的數據對象集合;命令引擎執行;導出引擎執行結果,從引擎中撤出處理過的數據。使用了規則引擎以後,許多涉及業務邏輯的 程序代碼基本被這五個典型步驟所取代。

一個開放的業務規則引擎應該能夠"嵌入"在應用程序的任何位置,不一樣位置的規則引擎可使用不一樣的規則集,用於處理不一樣的數據對象。此外,對使用引擎的數量沒有限制。

2.4 規則引擎架構與推理

規則引擎的架構以下圖所示:

圖2. 業務規則引擎架構
圖2. 業務規則引擎架構

規 則引擎的推理步驟以下:a. 將初始數據(fact)輸入至工做內存(Working Memory)。b. 使用Pattern Matcher將規則庫(Rules repository)中的規則(rule)和數據(fact)比較。c. 若是執行規則存在衝突(conflict),即同時激活了多個規則,將衝突的規則放入衝突集合。d. 解決衝突,將激活的規則按順序放入Agenda。e. 執行Agenda中的規則。重複步驟b至e,直到執行完畢Agenda中的全部規則。

任何一個規則引擎都須要很好地解決規則的推理機制和規則條件匹配的效率問題。

當 引擎執行時,會根據規則執行隊列中的優先順序逐條執行規則執行實例,因爲規則的執行部分可能會改變工做區的數據對象,從而會使隊列中的某些規則執行實例因 爲條件改變而失效,必須從隊列中撤銷,也可能會激活原來不知足條件的規則,生成新的規則執行實例進入隊列。因而就產生了一種"動態"的規則執行鏈,造成規 則的推理機制。這種規則的"鏈式"反應徹底是由工做區中的數據驅動的。

規則條件匹配的效率決定了引擎的性能,引擎須要迅速測試工做區中的 數據對象,從加載的規則集中發現符合條件的規則,生成規則執行實例。1982年美國卡耐基·梅隆大學的Charles L. Forgy發明了一種叫Rete算法,很好地解決了這方面的問題。目前世界頂尖的商用業務規則引擎產品基本上都使用Rete算法。

2.5 規則引擎的算法

大 部分規則引擎產品的算法,基本上都來自於Dr. Charles Forgy在1979年提出的RETE算法及其變體,Rete算法是目前效率最高的一個Forward-Chaining推理算法,Drools項目是 Rete算法的一個面向對象的Java實現,Rete算法其核心思想是將分離的匹配項根據內容動態構造匹配樹,以達到顯著下降計算量的效果。詳情請見 CIS587:The RETE Algorithm,The Rete Algorithm,RETE演算法,《專家系統原理與編程》中第11章等。

回頁首

三、 Java規則引擎

目前主流的規則引擎組件可能是基於Java和C++程序語言環境,已經有多種Java規則引擎商業產品與開源項目的實現,其中有的已經支持JSR94,有的正朝這個方向作出努力,列出以下:

3.1 Java規則引擎商業產品

Java規則引擎商業產品主要有(Jess不是開源項目,它能夠免費用於學術研究,但用於商業用途則要收費):

3.2 Java規則引擎開源項目

開源項目的實現主要包括:

Drools - Drools規則引擎應用Rete算法的改進形式Rete-II算法。從內部機制上講,它使用了和Forgy的算法相同的概念和方法,可是增長了可與面嚮對象語言無縫鏈接的節點類型。

Mandarax 基於反向推理(概括法)。可以較容易地實現多個數據源的集成。例如,數據庫記錄能方便地集成爲事實集(facts sets),reflection用來集成對象模型中的功能。目前不支持JSR 94

OFBiz Rule Engine - 支持概括法(Backward chaining).最初代碼基於Steven John Metsker的"Building Parsers in Java",不支持JSR 94

JLisa - JLisa是用來構建業務規則的強大框架,它有着擴展了LISP優秀特點的優勢,比Clips還要強大.這些特點對於多範例軟件的開發是相當重要的.支持JSR 94

其 它的開源項目實現有諸如Algernon, TyRuBa, JTP, JEOPS, InfoSapient, RDFExpert, Jena 2, Euler, JLog, Pellet OWL Reasoner, Prova, OpenRules, SweetRules, JShop2等等。

回頁首

四、 Java規則引擎API(JSR-94)

4.1 簡介

過 去大部分的規則引擎開發並無規範化,有其自有的API,這使得其與外部程序交互集成不夠靈活。轉而使用另一種產品時每每意味須要重寫應用程序邏輯和 API調用,代價較大。規則引擎工業中標準的缺少成爲使人關注的重要方面。2003年11月定稿並於2004年8月最終發佈的JSR 94(Java規則引擎API)使得Java規則引擎的實現得以標準化。

Java規則引擎API由javax.rules包定義,是訪問規 則引擎的標準企業級API。Java規則引擎API容許客戶程序使用統一的方式和不一樣廠商的規則引擎產品交互,就像使用JDBC編寫獨立於廠商訪問不一樣的 數據庫產品同樣。Java規則引擎API包括建立和管理規則集合的機制,在Working Memory中添加,刪除和修改對象的機制,以及初始化,重置和執行規則引擎的機制。

4.2 簡介Java規則引擎API體系結構

Java規則引擎API分爲兩個主要部分:運行時客戶API(the Runtime client API)和規則管理API(the rules administration API)。

4.2.1規則管理API

規 則管理API在javax.rules.admin中定義,包括裝載規則以及與規則對應的動做(執行集 execution sets)以及實例化規則引擎。規則能夠從外部資源中裝載,好比說URI,Input streams, XML streams和readers等等.同時管理API提供了註冊和取消註冊執行集以及對執行集進行維護的機制。使用admin包定義規則有助於對客戶訪問 運行規則進行控制管理,它經過在執行集上定義許可權使得未經受權的用戶沒法訪問受控規則。

管理API使用類 RuleServiceProvider來得到規則管理(RuleAdministrator)接口的實例.規則管理接口提供方法註冊和取消註冊執行集. 規則管理器(RuleAdministrator)提供了本地和遠程的RuleExecutionSetProvider.在前面已提 及,RuleExecutionSetProvider負責建立規則執行集.規則執行集能夠從如XML streams, input streams等來源中建立.這些數據來源及其內容經聚集和序列化後傳送到遠程的運行規則引擎的服務器上.大多數應用程序中,遠程規則引擎或遠程規則數據 來源的狀況並很少見.爲了不這些狀況中的網絡開銷,API規定了能夠從運行在同一JVM中規則庫中讀取數據的本地 RuleExecutionSetProvider.

規則執行集接口除了擁有可以得到有關規則執行集的方法,還有可以檢索在規則執行集中定義的全部規則對象.這使得客戶可以知道規則集中的規則對象而且按照本身須要來使用它們。

4.2.2 運行時API

運行時API定義在javax.rules包中,爲規則引擎用戶運行規則得到結果提供了類和方法。運行時客戶只能訪問那些使用規則管理API註冊過的規則,運行時API幫助用戶得到規則對話而且在這個對話中執行規則。

運 行時API提供了對廠商規則引擎API實現的相似於JDBC的訪問方法.規則引擎廠商經過類RuleServiceProvider(類 RuleServiceProvider提供了對具體規則引擎實現的運行時和管理API的訪問)將其規則引擎實現提供給客戶,並得到 RuleServiceProvider惟一標識規則引擎的URL.

URL推薦標準用法是使用類 似"com.mycompany.myrulesengine.rules.RuleServiceProvider"這樣的Internet域名空間, 這將有助於訪問URL的惟一性.類RuleServiceProvider內部實現了規則管理和運行時訪問所需的接口.全部的 RuleServiceProvider要想被客戶所訪問都必須用RuleServiceProviderManager進行註冊。註冊方式相似於 JDBC API的DriverManager和Driver。

運行時接口是運行時API的關鍵部分.運行時接口提供了用於建立規則會話 (RuleSession)的方法,規則會話如前所述是用來運行規則的.運行時API同時也提供了訪問在service provider註冊過的全部規則執行集(RuleExecutionSets).規則會話接口定義了客戶使用的會話的類型,客戶根據本身運行規則的方式 能夠選擇使用有狀態會話或者無狀態會話。

無狀態會話的工做方式就像一個無狀態會話bean.客戶能夠發送單個輸入對象或一列對象來得到輸出 對象.當客戶須要一個與規則引擎間的專用會話時,有狀態會話就頗有用.輸入的對象經過addObject() 方法能夠加入到會話當中.同一個會話當中能夠加入多個對象.對話中已有對象能夠經過使用updateObject()方法獲得更新.只要客戶與規則引擎間 的會話依然存在,會話中的對象就不會丟失。

RuleExecutionSetMetaData接口提供給客戶讓其查找規則執行集的元數據(metadata).元數據經過規則會話接口(RuleSession Interface)提供給用戶。

使用運行時Runtime API的代碼片段以下所示:

RuleServiceProvider ruleProvider = 
RuleServiceProviderManager.getRuleServiceProvider
("com.mycompany.myrulesengine.rules. RuleServiceProvider");   
RuleRuntime ruleRuntime = ruleProvider.getRuleRuntime();
StatelessRuleSession ruleSession = (StatelessRuleSession)  
ruleRuntime.createRuleSession(ruleURL, null, RuleRuntime.STTELESS_SESSION_TYPE);
List inputRules = new ArrayList();
inputRules.add(new String("Rule 1"));
inputRules.add(new Integer(1));
List resultRules = ruleSession.executeRules(inputRules);

4.3 Java規則引擎API安全問題

規 則引擎API將管理API和運行時API加以分開,從而爲這些包提供了較好粒度的安全控制.規則引擎API並無提供明顯的安全機制,它能夠和J2EE規 範中定義的標準安全API聯合使用.安全能夠由如下機制提供,如Java authentication and authorization service (JAAS),the Java cryptography extension (JCE),Java secure Socket Extension (JSSE),或者其它定製的安全API.JAAS能被用來定義規則執行集的許可權限,從而只有受權用戶才能訪問。

4.4 異常與日誌

規則引擎API定義了javax.rules.RuleException做爲規則引擎異常層次的根類.全部其它異常都繼承於這個根類.規則引擎中定義的異常都是受控制的異常(checked exceptions),因此捕獲異常的任務就交給了規則引擎。 規則引擎API沒有提供明確的日誌機制,可是它建議將Java Logging API用於規則引擎API。

4.5 JSR 94 小結

JSR 94 爲規則引擎提供了公用標準API,僅僅爲實現規則管理API和運行時API提供了指導規範,並無提供規則和動做該如何定義以及該用什麼語言定義規則,也 沒有爲規則引擎如何讀和評價規則提供技術性指導.JSR 94規範將上述問題留給了規則引擎的廠商.在下一節我將簡要介紹一下規則語言。

回頁首

五、 規則語言

JSR 94中沒有涉及用來建立規則和動做的語言.規則語言是規則引擎應用程序的重要組成部分,全部的業務規則都必須用某種語言定義而且存儲於規則執行集中,從而規則引擎能夠裝載和處理他們。

由 於沒有關於規則如何定義的公用規範,市場上大多數流行的規則引擎都有其本身的規則語言,目前便有許多種規則語言正在應用,所以,當須要將應用移植到其餘的 Java規則引擎實現時,可能須要變換規則定義,如將Drools私有的DRL規則語言轉換成標準的ruleML,Jess規則語言轉換成ruleML 等。這個工做通常由XSLT轉換器來完成。

規則語言的詳情這裏不做詳細介紹,名稱及其網址列出以下:

Rule Markup language (RuleML)                        http://www.ruleml.org/
Simple Rule Markup Language (SRML)                    http://xml.coverpages.org/srml.html
Business Rules Markup Language (BRML)                    http://xml.coverpages.org/brml.html
SWRL: A Semantic Web Rule Language Combining OWL and RuleML   http://www.daml.org/2003/11/swrl/

多 種規則語言的使用使得不一樣規則引擎實現之間的兼容性成爲問題.通用的規則引擎API或許能夠減輕不一樣廠家API之間的問題,但公用規則語言的缺少將仍然阻 礙不一樣規則引擎實現之間的互操做性.儘管業界在提出公用規則語言上作出了一些努力, 好比說RuleML,SRML的出現,但距離得到絕大部分規則引擎廠商贊成的公用標準還有很長的路要走。

回頁首

六、 Java規則引擎API使用示例

6.1 設置規則引擎

Java 規則引擎的管理活動階段開始於查找一個合適的javax.rules.RuleServiceProvider對象,這個對象是應用程序訪問規則引擎的入 口。在J2EE環境中,你可能能夠經過JNDI得到RuleServiceProvider。不然,你可使用 javax.rules.RuleServiceProviderManager類:

javax.rules.RuleServiceProviderManager class: 
           String implName = "org.jcp.jsr94.ri.RuleServiceProvider";
           Class.forName(implName);
           RuleServiceProvider 
serviceProvider = RuleServiceProviderManager.getRuleServiceProvider(implName);

擁 有了RuleServiceProvider對象,你就能夠得到一個javax.rules.admin.RuleAdministrator類。從 RuleAdministrator類中,你能夠獲得一個RuleExecutionSetProvider,從類名能夠知道,它用於建立 javax.rules.RuleExecutionSets對象。RuleExecutionSet基本上是一個裝入內存的,準備好執行的規則集合。

包 javax.rules.admin包括兩個不一樣的RuleExecutionSetProvider類。 RuleExecutionSetProvider類自己包括了從Serializable對象建立RuleExecutionSets的方法,所以在規 則引擎位於遠程服務器的狀況下,仍然可使用RuleExecutionSetProvider類,構造器的參數能夠經過RMI來傳遞。另外一個類是 LocalRuleExecutionSetProvider,包含了其餘方法,用於從非Serializable資源(如 java.io.Reader-本地文件)建立RuleExectionSets。假設擁有了一個RuleServiceProvider對象,你能夠從 本地文件rules.xml文件建立一個RuleExectionSet對象。如如下的代碼所示:

RuleAdministrator admin = serviceProvider.getRuleAdministrator();
          HashMap properties = new HashMap();
          properties.put("name", "My Rules");
          properties.put("description", "A trivial rulebase");
          FileReader reader = new FileReader("rules.xml");
          RuleExecutionSet ruleSet = null;
          try {
               LocalRuleExecutionSetProvider lresp =
               admin.getLocalRuleExecutionSetProvider(properties);
               ruleSet = lresp.createRuleExecutionSet(reader, properties);
          } finally {
               reader.close();
          }

接下來,你可使用RuleAdministrator註冊得到的 RuleExecutionSet,並給它分配一個名稱。在運行時,你能夠用同一個名稱建立一個RuleSession;該RuleSession使用了 這個命名的RuleExecutionSet。參見下面的用法:admin.registerRuleExecutionSet("rules", ruleSet, properties);

6.2 執行規則引擎

在運行時階段,你能夠參見一 個RuleSession對象。RuleSession對象基本上是一個裝載了特定規則集合的規則引擎實例。你從RuleServiceProvider 獲得一個RuleRuntime對象,接下來,從javax.rules.RuleRuntime獲得RuleSession對象。

RuleSession 分爲兩類:stateful和stateless。它們具備不一樣的功能。StatefulRuleSession的Working Memory可以在多個方法調用期間保存狀態。你能夠在多個方法調用期間在Working Memory中加入多個對象,而後執行引擎,接下來還能夠加入更多的對象並再次執行引擎。相反,StatelessRuleSession類是不保存狀態 的,爲了執行它的executeRules方法,你必須爲Working Memory提供全部的初始數據,執行規則引擎,獲得一個內容列表做爲返回值。

下 面的例子中,咱們建立一個StatefulRuleSession實例,添加兩個對象(一個Integer和一個String)到Working Memory,執行規則,而後獲得Working Memory中全部的內容,做爲java.util.List對象返回。最後,咱們調用release方法清理RuleSession:

RuleRuntime runtime = rsp.getRuleRuntime();
         StatefulRuleSession session = (StatefulRuleSession)
         runtime.createRuleSession("rules", properties,
         RuleRuntime.STATEFUL_SESSION_TYPE);
         session.addObject(new Integer(1));
         session.addObject("A string");
         session.executeRules();
         List results = session.getObjects();
         session.release();

回頁首

七、 結束語

Java 規則引擎API(JSR-94)容許客戶程序使用統一的方式和不一樣廠商的規則引擎產品交互,必定程度上給規則引擎廠商提供了標準化規範。但其幾乎沒有定義 什麼是規則引擎,固然也沒有深刻到規則是如何構建和操縱的,規則調用的效用,規則與Java語言的綁定等方面。而且JSR-94在對J2EE的支持上也不 足。規則語言的標準化,JSR-94的進一步的充實深化都有待研究。

參考資料

相關文章
相關標籤/搜索