基于Java注解的Drools業(yè)務(wù)規(guī)則開發(fā)框架設(shè)計(jì)實(shí)現(xiàn)
規(guī)則引擎由推理引擎發(fā)展而來,是一種嵌入在應(yīng)用程序中的組件,實(shí)現(xiàn)了將業(yè)務(wù)決策從應(yīng)用程序代碼中分離出來,并使用預(yù)定義的語義模塊編寫業(yè)務(wù)決策。規(guī)則引擎接受數(shù)據(jù)輸入,解釋業(yè)務(wù)規(guī)則,并根據(jù)業(yè)務(wù)規(guī)則做出業(yè)務(wù)決策。規(guī)則引擎適用于業(yè)務(wù)規(guī)則復(fù)雜且頻繁改動(dòng)的系統(tǒng)。
Drools是RedHat公司旗下一款基于Java語言的開源規(guī)則引擎,廣泛應(yīng)用于金融、保險(xiǎn)、電信等領(lǐng)域,可以將復(fù)雜多變的規(guī)則以規(guī)則腳本的形式存放在文件中,使得規(guī)則的變更不需要重啟機(jī)器就可以立即在線上環(huán)境生效。
在業(yè)務(wù)規(guī)則開發(fā)過程中,Drools規(guī)則引擎只能識(shí)別與處理基于DRL(Domain Rule Language)格式定義的業(yè)務(wù)邏輯,與Java程序相比存在著一些缺陷,不能很好地支持企業(yè)級(jí)應(yīng)用管理,主要表現(xiàn)在以下兩方面。
(1)開發(fā)效率待提高:DRL語法學(xué)習(xí)成本較高;傳統(tǒng)Java開發(fā)環(huán)境(例如Eclipse)不支持對(duì)DRL進(jìn)行語法檢查和語法輔助,無法在運(yùn)行前發(fā)現(xiàn)語法錯(cuò)誤;部分規(guī)則文件無法進(jìn)行調(diào)試;重構(gòu)難度大,進(jìn)行規(guī)則修改時(shí)很難評(píng)估影響范圍。
(2)代碼質(zhì)量缺乏保障:無法通過代碼質(zhì)量管理工具(例如SonarQube)對(duì)DRL文件進(jìn)行檢查與分析。
為解決這些缺陷,迫切需要建立Drools業(yè)務(wù)規(guī)則開發(fā)框架,直接使用Java語言實(shí)現(xiàn)業(yè)務(wù)邏輯,單元測(cè)試通過后自動(dòng)生成Drools業(yè)務(wù)規(guī)則。
Drools業(yè)務(wù)規(guī)則開發(fā)框架主要由編寫模塊、執(zhí)行模塊、轉(zhuǎn)換模塊三部分組成。其中編寫模塊定義Java語言實(shí)現(xiàn)業(yè)務(wù)邏輯的規(guī)范;執(zhí)行模塊對(duì)Java語言實(shí)現(xiàn)的業(yè)務(wù)邏輯模擬執(zhí)行,并支持在傳統(tǒng)Java開發(fā)環(huán)境中進(jìn)行代碼調(diào)試;轉(zhuǎn)換模塊將Java語言實(shí)現(xiàn)的業(yè)務(wù)邏輯轉(zhuǎn)換成Drools規(guī)則引擎支持的業(yè)務(wù)規(guī)則。
Drools業(yè)務(wù)規(guī)則開發(fā)框架的使用流程如圖1所示。
圖1 Drools業(yè)務(wù)規(guī)則開發(fā)框架的使用流程
通過使用此開發(fā)框架,技術(shù)人員直接使用Java語言實(shí)現(xiàn)業(yè)務(wù)邏輯,將極大提高開發(fā)效率和代碼質(zhì)量。
下面介紹Drools業(yè)務(wù)規(guī)則開發(fā)框架的實(shí)現(xiàn)技術(shù)。
2.1 Java注解技術(shù)
注解(annotation)是JDK1.5及以后版本引入的一個(gè)特性。注解(annotation)是一個(gè)接口,程序可以通過反射來獲取指定程序元素的注解對(duì)象,然后通過注解對(duì)象來獲取注解里面的元數(shù)據(jù)。
元注解(meta-annotation)的作用是負(fù)責(zé)注解其他注解。Java5.0定義了4個(gè)標(biāo)準(zhǔn)的元注解類型,它們被用來提供對(duì)其它 注解類型作說明。其中元注解@Target說明了注解所修飾的對(duì)象范圍,元注解@Retention定義了該注解被保留的時(shí)間長短,分為三種情況:SOURCE表示出現(xiàn)在源代碼中但被編譯器丟棄;CLASS表示編譯在class文件中但在class文件裝載時(shí)被忽略;RUNTIME表示編譯在class文件中且在class裝載時(shí)被讀取。
Java注解技術(shù)對(duì)于Drools業(yè)務(wù)規(guī)則開發(fā)框架至關(guān)重要?;谧⒔饧夹g(shù),執(zhí)行模塊獲取代碼中的元注解信息從而動(dòng)態(tài)執(zhí)行Java代碼,轉(zhuǎn)換模塊獲取代碼中的元注解信息從而完成代碼分析從而轉(zhuǎn)換為DRL文件。
2.2 編寫模塊
編寫模塊中定義了三種注解,分別為RuleGroup、Rule、RuleFunction,這三種注解的@Retention都設(shè)置為RUNTIME,以便在執(zhí)行模塊及轉(zhuǎn)換模塊中獲取注解信息。
RuleGroup標(biāo)識(shí)在規(guī)則流中所屬的節(jié)點(diǎn),定義如下:
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface RuleGroup {
String ruleflowGroup();
}
Rule標(biāo)識(shí)業(yè)務(wù)規(guī)則屬性,如優(yōu)先級(jí)。定義如下:
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Rule {
String salience() default "10000";
}
RuleFunction標(biāo)識(shí)業(yè)務(wù)規(guī)則中調(diào)用的函數(shù)方法。定義如下:@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface RuleFunction {
}
基于這三種注解,使用Java語言編寫的業(yè)務(wù)邏輯示例如下:@RuleGroup(ruleflowGroup="RequestRules")
public class RequestRules {
@Rule(salience = "10000")
public static class Rule1 {
public boolean when() { return true;
}
public void then() {
func1();
}
}
@RuleFunction
static void func1() {
}
}
從以上示例可以看到,技術(shù)人員使用Java語言實(shí)現(xiàn)業(yè)務(wù)邏輯,能夠進(jìn)行語法檢查和語法輔助,也能通過代碼質(zhì)量管理工具保證代碼的規(guī)范性。
2.3 執(zhí)行模塊
執(zhí)行模塊采用反射技術(shù)加載Java語言編寫的業(yè)務(wù)邏輯并執(zhí)行,處理流程如圖2所示。
圖2 執(zhí)行模塊處理流程圖
具體處理流程如下:
(1)按規(guī)則流節(jié)點(diǎn)順序加載使用RuleGroup注解的類;
(2)獲取類中使用Rule注解的內(nèi)部類并按salience排序;(3)按順序執(zhí)行各內(nèi)部類;
①實(shí)例化內(nèi)部類innerRule;
②如果innerRule.when()結(jié)果為true則執(zhí)行inner Rule.then(),否則回到①實(shí)例化下一個(gè)內(nèi)部類。
業(yè)務(wù)規(guī)則when部分的輸入為字符串,輸出為true或false,類似于Javascript中的eval()函數(shù)。執(zhí)行模塊采用規(guī)則引擎加載此字符串并執(zhí)行,核心代碼如下:
// 加載DRL并執(zhí)行
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory. newKnowledgeBuilder();
kbuilder add(ResourceFactory newReaderResource(strReade r),ResourceType.DRL);
KnowledgeBase kbase = kbuilder.newKnowledgeBase();
StatefulKnowledgeSession ksession = kbase. newStatefulKnowledgeSession();
ksession insert(messageWrapper);
QueryResults results = ksession.getQueryResults(drlHash);
// 對(duì)執(zhí)行結(jié)果進(jìn)行判斷
return (results.size() > 0);
2.4 轉(zhuǎn)換模塊
轉(zhuǎn)換模塊將Java文件轉(zhuǎn)換為Drools規(guī)則引擎支持的DRL文件,處理流程如圖3所示。
圖3 轉(zhuǎn)換模塊處理流程圖
具體處理流程如下:
(1)按規(guī)則流節(jié)點(diǎn)順序加載Java文件;
(2)使用開源的google JavaParser庫進(jìn)行Java文件解析;
(3)對(duì)使用Rule注解的內(nèi)部類進(jìn)行循環(huán)處理,獲取ruleflow-group屬性、salience屬性、when部分、then部分及function部分;
(4)將生成的符合Drools業(yè)務(wù)規(guī)則語法的字符串寫入DRL文件。
從全球民航發(fā)展情況看,由于市場(chǎng)競(jìng)爭(zhēng)不斷加劇,全球民航業(yè)長期處于微利運(yùn)營水平。在日益艱難的市場(chǎng)環(huán)境中,國內(nèi)外航空公司在客運(yùn)方面力圖沖破只能提供航空運(yùn)輸?shù)膫鹘y(tǒng)服務(wù)模式,不斷探索新的商務(wù)模式和盈利渠道,正在發(fā)展成為以航空運(yùn)輸為中心、集酒店、租車、旅游、免稅品銷售等服務(wù)于一體的航空旅游綜合服務(wù)提供商[4]。航空公司機(jī)票+酒店動(dòng)態(tài)打包銷售平臺(tái)項(xiàng)目(簡(jiǎn)稱動(dòng)態(tài)打包項(xiàng)目)正是在這個(gè)大背景下立項(xiàng)并實(shí)施的。
在開發(fā)動(dòng)態(tài)打包項(xiàng)目時(shí),采用了Drools規(guī)則引擎,基于規(guī)則流(RuleFlow)技術(shù)實(shí)現(xiàn)動(dòng)態(tài)打包查詢、預(yù)訂、取消等功能,輸入輸出遵循OTA(Open Travel Alliance)國際標(biāo)準(zhǔn)。
在實(shí)現(xiàn)中,將輸入輸出抽象為MessageWrapper,將每個(gè)功能的業(yè)務(wù)處理流程進(jìn)行總結(jié),抽象為RequestRules、SwitchingRules、AggregationRules、ResponseOptionRules、ResponseRules共5個(gè)節(jié)點(diǎn),分別實(shí)現(xiàn)請(qǐng)求校驗(yàn)、外部系統(tǒng)調(diào)用、外部系統(tǒng)結(jié)果合并、響應(yīng)結(jié)果過濾與排序、響應(yīng)結(jié)果處理(如促銷價(jià)格計(jì)算)功能。節(jié)點(diǎn)名稱與RuleGroup中的ruleflowGroup屬性相對(duì)應(yīng)。每個(gè)節(jié)點(diǎn)內(nèi)的業(yè)務(wù)規(guī)則按優(yōu)先級(jí)順序執(zhí)行,整體業(yè)務(wù)處理流程如圖4所示。
圖4 業(yè)務(wù)處理流程圖
為驗(yàn)證開發(fā)框架在提高開發(fā)效率方面的效果,項(xiàng)目組選取動(dòng)態(tài)打包查詢模塊進(jìn)行比對(duì)實(shí)驗(yàn)。選取兩個(gè)水平接近的開發(fā)人員,以通過預(yù)先設(shè)定的單元測(cè)試為完成標(biāo)準(zhǔn),采用直接編寫DRL文件的開發(fā)方式共花費(fèi)15人天,采用開發(fā)框架共花費(fèi)11人天。
根據(jù)以上比對(duì)實(shí)驗(yàn),通過使用Drools業(yè)務(wù)規(guī)則開發(fā)框架,動(dòng)態(tài)打包項(xiàng)目提高開發(fā)效率20%以上,節(jié)省至少5人月開發(fā)工作量。同時(shí)在SonarQube中代碼質(zhì)量評(píng)級(jí)為A,取得預(yù)期效果。
利用基于Java注解的Drools業(yè)務(wù)規(guī)則開發(fā)框架,技術(shù)人員可以方便的進(jìn)行業(yè)務(wù)規(guī)則編寫、調(diào)試,提升代碼質(zhì)量,提高開發(fā)效率。
動(dòng)態(tài)打包項(xiàng)目中每個(gè)節(jié)點(diǎn)內(nèi)的業(yè)務(wù)規(guī)則按優(yōu)先級(jí)順序執(zhí)行,沒有涉及規(guī)則的重復(fù)觸發(fā)與沖突檢測(cè),后續(xù)還需要持續(xù)改進(jìn)完善。
[1]張淵,夏清國.基于Rete算法的JAVA規(guī)則引擎[J].科學(xué)技術(shù)與工程,2006,6(11) :1548-1550.
[2]李春芳,譚慶平. 面向業(yè)務(wù)的 Drools規(guī)則引擎改進(jìn)[J]. 計(jì)算機(jī)應(yīng)用與軟件,2015,32(5) :20-23.
[3]凌晨,陳芳莉.Java注釋類型和APT [J]. 計(jì)算機(jī)系統(tǒng)應(yīng)用,2006,15(9):78-82.
[4]王欣明,呂明站.民航附加服務(wù)動(dòng)態(tài)打包技術(shù)研究[J]. 民航科技,2011(3):39-42.
[5]繳明洋,譚慶平. Java規(guī)則引擎技術(shù)研究[J]. 計(jì)算機(jī)與信息技術(shù),2006(3) :44-46.
周中雨(1978——),男,河北省河間市,中級(jí)工程師,碩士研究生,主要從事J2EE平臺(tái)軟件架構(gòu)設(shè)計(jì)及研發(fā)。
李洋(1977——),男,陜西省藍(lán)田縣,中級(jí)工程師,碩士研究生,主要從事J2EE平臺(tái)軟件架構(gòu)設(shè)計(jì)及研發(fā)。
王懷超(1984——),男,天津,講師,博士研究生,主要研究方向航空物流、計(jì)算機(jī)視覺。
楊程屹(1986——),男,河北省灤縣,中級(jí)工程師,博士研究生,主要從事數(shù)據(jù)挖掘、算法研究等工作。
周中雨1,李洋1,楊程屹1,王懷超2
(1.中國民航信息網(wǎng)絡(luò)股份有限公司,北京,100105;2.中國民航大學(xué)計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院,天津,300300)
本文設(shè)計(jì)并實(shí)現(xiàn)了基于Java注解的規(guī)則引擎Drools業(yè)務(wù)規(guī)則開發(fā)框架。該開發(fā)框架針對(duì)Drools業(yè)務(wù)規(guī)則存在的無法語法檢查、無法調(diào)試等問題,基于Java注解技術(shù),直接使用Java語言實(shí)現(xiàn)業(yè)務(wù)邏輯,單元測(cè)試通過后生成Drools業(yè)務(wù)規(guī)則,從而提升代碼質(zhì)量并提高開發(fā)效率。
規(guī)則引擎;Drools;業(yè)務(wù)規(guī)則;Java注解;Java反射
Design and Implementation on Framework for Developing Drools Business Rules Based on Java Annotation
Zhou Zhongyu1,Li Yang1,Yang Chengyi1,Wang Huaichao2
(1.Travelsky Technology Limited,Beijing,100105;2.College of Computer Science and Technology, Civil Aviation University of China,Tianjin,300300)
We design and implement a framework for developing Drools business rules based on Java annotation in order to solve the problems such as absence of syntax checking, difficulty of debugging, etc. Using the framework developers implement business logic in Java language and translate Java files to Drools business rules after passing the unit test The framework is designed to improve code quality and efficiency
Rule Engine;Drools;Business Rules;Java Annotation;Java Reflect
2013年民航科技創(chuàng)新引導(dǎo)項(xiàng)目(MHRD20130216)。