馬娜
摘要:作為面向服務(wù)計算泛型的一種重要實現(xiàn)手段,OSGi為構(gòu)建具有模塊化、“即插即用”、可動態(tài)持續(xù)演化的軟件系統(tǒng),提供了一個強大的通用化平臺和規(guī)范支持。針對層次化類裝載器代理體系下,OSGi服務(wù)平臺中類資源裝載沖突問題,從基于Java平臺的OSGi類裝載體系出發(fā),對造成類資源沖突的基本原理進行分析,給出消解沖突的基本原則。提出了遵循該原則的基于第三方共享Bundle、及靜態(tài)和動態(tài)資源沖突檢測的沖突消解方法,并給出了方法的具體實現(xiàn)方式。
關(guān)鍵詞:Java類裝載器;OSGi;類資源沖突;沖突消解方法
中圖分類號:TP311 文獻標識碼:A 文章編號:1009-3044(2016)15-0074-04
隨著計算機軟件與互聯(lián)網(wǎng)技術(shù)的快速發(fā)展,軟件計算泛型大致經(jīng)歷了從面向?qū)ο?、面向?gòu)件到面向服務(wù)計算(SOC)泛型的轉(zhuǎn)變。SOC是一種以服務(wù)為基本元素,進行軟件應(yīng)用和解決方案設(shè)計、實現(xiàn)的軟件計算范型,反映了自治、異構(gòu)的互聯(lián)網(wǎng)環(huán)境中軟件的構(gòu)件化趨勢[1]。近年來,得到廣泛關(guān)注的云計算技術(shù)也是以服務(wù)為核心的一種新的應(yīng)用與商業(yè)模式[2]。
OSGi是具有開放、通用軟件架構(gòu)的服務(wù)平臺規(guī)范,為服務(wù)提供者、開發(fā)者等提供一種協(xié)作完成服務(wù)開發(fā)、部署與管理的模式[3],是SOC泛型的一種重要實現(xiàn)手段[4]。OSGi支持基于可復用服務(wù)插件的可插拔軟件系統(tǒng)的構(gòu)建,能以插件為粒度實現(xiàn)軟件行為的動態(tài)改變,通過插件間隔離保障系統(tǒng)運行時的穩(wěn)定性與可靠性。目前,OSGi已得到眾多企業(yè)、廠商、開源組織的支持,如Apache、Eclipse、Spring等,并已成為事實上的Java模塊化公認、通用標準[5]。目前,OSGi技術(shù)已在智能家庭網(wǎng)絡(luò)[6],嵌入式軟件[7,8],傳感器網(wǎng)絡(luò)[9]等領(lǐng)域得到關(guān)注與初步應(yīng)用。
OSGi的類裝載機制,提供了靈活、安全、獨立的類裝載能力,但常常導致潛在的類資源的裝載沖突問題,進而提高Bundle開發(fā)、第三方Bundle集成的復雜性,增加系統(tǒng)實施的成本,甚至限制OSGi技術(shù)在大型、專業(yè)軟件公司之外的普適性推廣與應(yīng)用能力。因此,理解和掌握OSGi服務(wù)平臺技術(shù)體系下類資源沖突機理,并采用適合的消解方法,已成為該領(lǐng)域基礎(chǔ)理論研究與發(fā)展,及工程實施與應(yīng)用推廣所面臨的重要基礎(chǔ)性問題之一。
1 相關(guān)技術(shù)
OSGi服務(wù)平臺中Bundle相關(guān)的類資源裝載,依賴于Java平臺的虛擬機的實現(xiàn)(如無特殊說明,下文提及虛擬機均指代Java虛擬機)。
虛擬機的主要任務(wù)是裝載Class文件,生產(chǎn)字節(jié)碼,并將字節(jié)碼交由運行時引擎執(zhí)行[10]。類裝載器是虛擬機一個重要的組件,負責完成從應(yīng)用程序和Java API中裝載Class文件,Java API實際上是Java平臺提供的系統(tǒng)類資源。同一個虛擬機中可以存在多個類裝載器的實例,形成靈活的虛擬機運行時類裝載器體系,如圖1所示:
不同類型的類裝載器實例,構(gòu)成了一個運行時類裝載的代理體系,形成類裝載器的父/子層次關(guān)系。當虛擬機需裝載某一Class文件時,會從應(yīng)用類裝載器(如存在)開始,逐層代理給系統(tǒng)類裝載器、擴展類裝載器和啟動類裝載器。子裝載器會為其父裝載器提供一個類裝載機會,以便裝載任何給定的類,并且只有父裝載器失敗時,其子裝載器才會進行類的裝載[11]。上述類裝載器在裝載類時,實際上是搜索不同的Class文件的存放路徑。例如:擴展類裝載器搜索Java平臺的ext目錄,而應(yīng)用類裝載器搜索自定義的類存放路徑,可以是本地文件系統(tǒng),也可以是網(wǎng)絡(luò)文件目錄。
理解裝載器體系的代理關(guān)系,以及不同類型裝載器的Class文件搜索方式,是理解OSGi技術(shù)體系下類資源沖突的基礎(chǔ),本文將在第2節(jié)對這種沖突的成因和機理進行分析。
2 沖突機理分析
虛擬機層次化、可擴展的代理裝載體系,能控制不同來源的Class文件中裝載類資源之間的相互影響,這種特性是OSGi通過類裝載機制實現(xiàn)不同Bundle間運行時隔離的技術(shù)基礎(chǔ)。正因為如此,OSGi規(guī)范的實現(xiàn)(Felix、Equinox)綁定為Java平臺,而非諸如.NET、C++等語言平臺。
Bundle是OSGi實現(xiàn)Java模塊化的最基本單元,Bundle的類資源可以從多種途徑獲得,包括:Java平臺的系統(tǒng)類資源,通過import、require和fragment方式來自其他Bundle的類資源,以及Bundle本地私有的類資源[3]。每個Bundle均擁有一獨立的類裝載器負責本地類資源的裝載,并共享Java虛擬機、OSGi容器提供的全局性類裝載器。為了保證模塊的隔離性,Bundle間通過導出和導入包的方式,隱藏內(nèi)部實現(xiàn)細節(jié),并通過服務(wù)接口調(diào)用其他Bundle提供的服務(wù)。這種機制下,Bundle間的接口調(diào)用是一種典型的客戶/服務(wù)器關(guān)系。基于Java平臺的Bundle間類資源的典型關(guān)系如圖2所示:
Bundle A可使用本地類資源,也可通過導入關(guān)系,使用Bundle B的本地類資源;可通過系統(tǒng)Bundle獲得Java平臺提供的類資源。OSGi定義了一套滿足模塊化隔離性的類裝載機制,因篇幅所限本文不再詳述,可參加文獻[3]。本文以Apache Felix OSGi實現(xiàn)為例,根據(jù)圖2分析OSGi技術(shù)體系下類資源的裝載過程,如圖3所示。
Bundle A定義和其本地路徑的類由Bundle A的私有類裝載器負責裝載;以Java.*開頭的包中的類由Felix框架的啟動類裝載器裝載(與虛擬機的啟動根裝載器不同);由Bundle B導出,Bundle A導入的類,則由Bundle B的類裝載器負責裝載;其他諸如虛擬機的擴展和系統(tǒng)路徑下的類,則通過Felix代理給虛擬機的類裝載器,按圖1所示虛擬機代理裝載器機制裝載。
上述基于虛擬機的類裝載體系中,不同的類或相同的類均可能被不同類型的類裝載器裝載,或者不同應(yīng)用類裝載實例裝載。通過類裝載器,構(gòu)建了Java平臺運行時的多個命名空間,這種命名空間由類裝載器、類的包名和類的名稱進行唯一標識。因此,來自不同搜索路徑下具有相同包名和類名的類,由于其命名空間的不同,將被虛擬機以不同的類定義對待。這種情況下,Bundle間傳遞不同命名空間中的同名類,就會出現(xiàn)類資源沖突問題。此外,OSGi對Bundle及其內(nèi)部Java包的版本信息進行嚴格限定,允許Bundle的不同版本同時存在于虛擬機運行時環(huán)境,這也可能引發(fā)類資源沖突,將在第3節(jié)消解方法中說明版本原因造成的沖突問題及消解方法。
3 消解方法
OSGi技術(shù)體系下的類資源沖突問題,為采用OSGi服務(wù)平臺進行工程實施與應(yīng)用帶來了大量的潛在風險與問題。運行時類資源沖突問題的引入原因多種多樣,本文以圖4(a)和(b)所示Bundle間關(guān)系為例,分析運行時類資源沖突問題引入的典型場景。
圖4(a)中,Bundle A調(diào)用Bundle B提供的Invoke服務(wù)方法,該服務(wù)需傳入類型為Class C的參數(shù)實例,Bundle A和Bundle B均將Class C作為本地類資源使用。虛擬機運行時類資源裝載時,Bundle A和Bundle B使用各自的私有類裝載器裝載Class C。由Bundle A創(chuàng)建并傳遞給Invoke服務(wù)方法的Class C實例,與Bundle B初始化Invoke服務(wù)時的Class C的類定義,隸屬于不同類裝載器命名空間。在Invoke服務(wù)方法調(diào)用時,將會出現(xiàn)運行時類資源裝載沖突問題。
圖4(b)中,Bundle A在本地有subClass和Class para兩個類資源,且前者依賴于后者。subClass是Bundle B本地的parentClass的子類,Bundle A通過導入關(guān)系,引用parentClass。Bundle B的parentClass類依賴于Class para類,但Bundle B本地沒有該類資源,而是通過導入Bundle C的本地類資源,獲得Class para類的引用。當Bundle A裝載subClass時會委托Bundle B加載其父類parentClass,而subClass和parentClass所依賴的Class para類資源,分別由Bundle A和Bundle C的私有類裝載器進行裝載。此時,虛擬機在運行時進行subClass類的連接過程中,會產(chǎn)生類資源裝載沖突問題。
根據(jù)對上述典型場景及第二節(jié)沖突機理分析結(jié)果可知,導致OSGi技術(shù)體系下類資源沖突的根本原因是,不同Bundle間類由于參數(shù)傳遞、運行時鏈接等情況下,相同類資源被不同類裝載器多次裝載??赏茖С鱿@種沖突的基本原則是,限定Bundle間由某一確定的類裝載器從確定的搜索路徑下裝載“共享”類資源,可以是虛擬機提供的類裝載器、OSGi提供的啟動類裝載器或某Bundle私有的類裝載器。為了滿足該沖突消解原則,總體而言可以有以下三種消解方法:
1) 對OSGi實現(xiàn)進行修訂,已得到OSGi系統(tǒng)平臺的支持??蛇m應(yīng)性修改OSGi實現(xiàn)的類裝載過程,當出現(xiàn)沖突時,由平臺自身選擇某確定的類裝載器進行裝載。這種修訂必將破壞OSGi的規(guī)范性和通用性,無法保證對所有潛在類裝載沖突消解的覆蓋性,并且實現(xiàn)的復雜性和成本過高。
2) 將共享類資源統(tǒng)一歸并到Java平臺,即將其駐存在虛擬機自身可搜索到的默認路徑,例如Windows操作系統(tǒng)下CLASSPATH配置的系統(tǒng)路徑或者jre/lib/ext的擴展路徑。需注意的是,一旦共享類資源放入擴展路徑,如類需調(diào)用系統(tǒng)類或擴展類,擴展類裝載器將無法裝載。然而,虛擬機是相對底層的系統(tǒng)軟件,這種方式某種程度上破壞了Java平臺自身的通用性。
3) 設(shè)計時引入獨立的第三方共享Bundle(可以是普通Bundle、Fragment Bundle、或Extension Bundle,相關(guān)細節(jié)可參考文獻[3]),將需共享的類資源統(tǒng)一裝配到共享Bundle,并導出需共享的類資源,依賴于共享類資源的Bundle均通過共享Bundle導入。采取基于Bundle裝箱單(即MANIFEST.MF文件)[3]的靜態(tài)沖突檢測,及運行時動態(tài)沖突檢測與報警機制,規(guī)避設(shè)計時和運行時潛在的類資源沖突問題。該方法,不依賴虛擬機或OSGi平臺的實現(xiàn),完全取決于設(shè)計時對Bundle間關(guān)系的規(guī)劃;對虛擬機或OSGi平臺的實現(xiàn)不造成破壞,具有較好的靈活性,無論是自研還是集成第三方提供的Bundle,均適用于此方法。
3.1 類資源沖突消解架構(gòu)
通過對以上3種可能的類資源沖突消解方法的分析,且考慮到實現(xiàn)復雜性、成本及Bundle版本等方面的因素,本文建議采用方法3)。根據(jù)方法3),具體的類資源裝載沖突消解方式如圖5所示:
第三方共享Bundle的引入,實際上是將多個Bundle共享類資源,委托給共享Bundle進行管理和裝載,將共享類資源存放在共享Bundle的本地路徑,由其私有類裝載器負責裝載共享類資源。這種方式,共享類資源的運行時裝載,將明確由共享Bundle私有類裝載器從其本地路徑進行裝載,從而避免多裝載器重復裝載時出現(xiàn)的類資源沖突問題。
3.2 靜態(tài)資源沖突檢測
靜態(tài)沖突檢測工具依賴于裝箱單文件,在設(shè)計時分析Bundle間的依賴關(guān)系,并對潛在的類資源版本引用沖突進行檢查。裝箱單是OSGi服務(wù)平臺的重要特征,可記錄Bundle基本配置信息及類資源引用信息,其具體功能可參見文獻[3]。
通過分析各個Bundle的裝箱單中的Import-Package,Require-Package,F(xiàn)ragment-Host、Bundle-ClassPath等配置信息,靜態(tài)沖突檢測工具可以在設(shè)計時分析Bundle間靜態(tài)引用關(guān)系;進一步地,根據(jù)OSGi裝載體系與過程,構(gòu)建各個Bundle間類裝載器代理關(guān)系,形成類裝載器代理網(wǎng)絡(luò)結(jié)構(gòu)圖。在此基礎(chǔ)上,可同時分析引用關(guān)系中版本信息可能引發(fā)的潛在類資源沖突問題。以圖5為例,Bundle A和B分別從Shared Bundle導入版本為1.0和1.1的Class para類資源,此時如果Bundle A和B存在依賴關(guān)系,則靜態(tài)沖突檢測工具會對其進行預警反饋,以對軟件系統(tǒng)設(shè)計優(yōu)化進行指導,并消除潛在類資源沖突。
3.3 動態(tài)資源沖突檢測
OSGi服務(wù)平臺的核心優(yōu)勢之一是模塊化的“即插即用”,保障軟件系統(tǒng)運行時的行為動態(tài)演化能力。當在運行時動態(tài)添加、替換Bundle時,需要一種運行時類資源沖突檢測的手段,為此,本文提供一種如圖5所示的動態(tài)沖突檢測方法。
該方法依賴于OSGiSystem Bundle提供的基于系統(tǒng)事件發(fā)布器的系統(tǒng)事件訂閱/發(fā)布機制。System Bundle啟動時會主導其他Bundle的安裝及其類資源裝載的過程(如Felix System Bundle的初始化與啟動方法),并維護其運行時生命周期狀態(tài),例如:Bundle的安裝、解析、啟動、卸載等。當某Bundle狀態(tài)發(fā)生改變時,會通過系統(tǒng)事件發(fā)布器對外發(fā)布相應(yīng)的系統(tǒng)事件。
基于這種事件機制,本文實現(xiàn)一個用于監(jiān)聽系統(tǒng)事件的動態(tài)沖突檢測Bundle,簡稱DCBundle,用于完成OSGi服務(wù)平臺運行時出現(xiàn)添加或替換Bundle情況下的類資源沖突的檢測。DCBundle的主要工作過程如下:
1) 在被System Bundle啟動時將自身注冊到系統(tǒng)事件發(fā)布器,成為系統(tǒng)事件的監(jiān)聽者,并將自身設(shè)定為非工作狀態(tài);
2) 整個OSGi平臺啟動完成后,接收一個外部命令,將自身設(shè)定為工作狀態(tài);
3) 監(jiān)聽、捕獲系統(tǒng)事件發(fā)布器的Bundle安裝事件,將新安裝的Bundle信息記錄在檢測隊列;
4) 監(jiān)聽、捕獲系統(tǒng)事件器發(fā)布的Bundle解析事件,獲取其Revision和BundleWiring對象(可認為是Bundle裝箱單文件的運行時內(nèi)存結(jié)構(gòu)),并進行運行時類資源沖突檢測;
5) 如存在類資源沖突,則通知動態(tài)沖突監(jiān)視工具,否則將新安裝的Bundle從檢測隊列中移除,并繼續(xù)監(jiān)聽系統(tǒng)事件。
4應(yīng)用與分析
本文在Eclipse3.6集成開發(fā)環(huán)境,開發(fā)實現(xiàn)了基于Felix和Equinox兩套OSGi服務(wù)平臺的靜態(tài)沖突檢測工具、動態(tài)沖突檢測Bundle及動態(tài)沖突監(jiān)視工具,并將其應(yīng)用于北京衛(wèi)星信息工程研究所自主研發(fā)的××云計算軟件平臺(以下簡稱云平臺)的類資源沖突檢測。該平臺的軟件架構(gòu)如圖6所示。
IaaS和PaaS層共提供了7類基礎(chǔ)軟件服務(wù),這些軟件服務(wù)均采用OSGi標準,以Bundle為基本模塊實現(xiàn)。其中,某些服務(wù)基于開源項目Hadoop1.0版本,進行完善和適應(yīng)性修改。自研部分也應(yīng)用某些第三方Java包或Bundle實現(xiàn),例如SL4J、Spring DM等。
目前,整個平臺的基礎(chǔ)服務(wù)涉及1200多個Bundle的調(diào)試與集成。Bundle間存在類資源依賴關(guān)系、本地類資源沖突與版本一致性等較為復雜的關(guān)系。由于動態(tài)沖突檢測時涉及的Bundle數(shù)目一般較少,本文重點對靜態(tài)沖突檢測進行測試,在Intel Core TM處理器E7500,雙核2.93GHz,內(nèi)存1.96GB的臺式機上進行實驗。本文對每個實驗重復10次,得到其平均靜態(tài)沖突檢測時間。結(jié)果如表1所示:
表1中,隨Bundle規(guī)模的增大,檢測時間也會增多,但所用時間并非線性增加。除Bundle規(guī)模外,Bundle間的依賴關(guān)系、對Java 平臺提供的類資源的依賴程度等,也是影響靜態(tài)沖突檢測時間的因素。在此,本文并未對其他因素的影響進行分類和試驗分析,將在后續(xù)工作中進行深入研究與分析。
從實驗結(jié)果看,本文提供的靜態(tài)沖突檢測工具,與SourceCounter、Findbugs、CheckStyle等用于代碼量統(tǒng)計及靜態(tài)分析工具的時間效率相當,可做為項目與工程實施中的應(yīng)用工具使用。
5總結(jié)
OSGi特有的層次化類裝載器代理體系,及私有類裝載機制的實現(xiàn),是其重要的基礎(chǔ)性核心技術(shù)之一。這種內(nèi)核機制所引發(fā)的潛在類資源裝載沖突問題,限制了其在大型、專業(yè)軟件公司之外的普適性推廣與應(yīng)用能力。本文從Java平臺類裝載體系出發(fā),分析引發(fā)OSGi技術(shù)體系下類資源裝載沖突的原因與機理,并給出實現(xiàn)沖突消解的基本原則。在此基礎(chǔ)上,分析了三種可能的沖突消解方法,對基于第三方共享Bundle、及靜態(tài)和動態(tài)資源沖突檢測的沖突消解方法進行詳細的說明,并給出該方法在實際工程應(yīng)用效果。
當前,OSGi技術(shù)已引起了學術(shù)界、工業(yè)界的高度重視,類資源裝載沖突問題及其解決方法,是該領(lǐng)域的重要基礎(chǔ)應(yīng)用問題之一。希望通過本文對類裝載沖突問題的成因與技術(shù)原理的分析,及沖突消解方法的探討,能為該領(lǐng)域基礎(chǔ)理論研究與工程化應(yīng)用提供有用的支撐,并引起國內(nèi)對OSGi內(nèi)核基礎(chǔ)技術(shù)的更廣泛關(guān)注與深入研究。
參考文獻:
[1] Huhns, M N Munindar P. Singh. Service-Oriented Computing Key Concepts and Principles [J],IEEE Internet Computing Magazine, 2005, 9(1): 75-81.
[2] Lamia Youseff, Maria Butrico, Toward a Unifed Ontology of Cloud Computing[C],GCE08, Austin, Texas, USA, 2008:1-10.
[3] OSGi Alliance, OSGi Service Platform Core Specification Release 5[EB/OL], 2012, http://www.osgi.org/Specifications/.
[4] Jingang Zhou, Dazhe Zhao, Examining OSGi from an Ideal Enterprise Software Component Model[C], ICSESS2010, Beijing University of Technology, Beijing, 2010:121-125.
[5] 林昊,曾憲杰.OSGI原理與最佳實踐[M].北京:電子工業(yè)出版社,2010.
[6] 周新華,曹奇英.智能家庭網(wǎng)關(guān)的OSGi R3實現(xiàn)[J].計算機工程與設(shè)計,2005,26(2):372-374.
[7] 姜華,苗克堅.基于OSGi服務(wù)網(wǎng)關(guān)的溫度報警系統(tǒng)的設(shè)計[J].計算機工程與設(shè)計,2009,30(18):4177-4179.
[8] 楊林,王晶,等.基于OSGi的移動廣告平臺訂單系統(tǒng)[J].計算機系統(tǒng)應(yīng)用,2011,20(3):32-36.
[9] 陳學文,范訓禮.基于OSGi的傳感器網(wǎng)絡(luò)服務(wù)體系結(jié)構(gòu)[J].計算機工程,2010,36(5):97-99.
[10] Bill Venners.深入Java虛擬機[M].2版.北京:工業(yè)機械出版社,2003.
[11] Cay S.Horstmann,Gary Cornell.Java核心技術(shù)卷Ⅱ[M].北京:工業(yè)機械出版社,2011.