版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、 火龍果整理 1.OSGi是什么:Java語言的動態(tài)模塊系統(tǒng)本文介紹了OSGi是什么,以及OSGi容器的一些現(xiàn)狀。OSGi亦稱做Java語言的動態(tài)模塊系統(tǒng),它為模塊化應(yīng)用的開發(fā)定義了一個(gè)基礎(chǔ)架構(gòu)。OSGi是什么OSGi亦稱做Java語言的動態(tài)模塊系統(tǒng),它為模塊化應(yīng)用的開發(fā)定義了一個(gè)基礎(chǔ)架構(gòu)。OSGi容器已有多家開源實(shí)現(xiàn),比如Knoflerfish、Equinox和Apache的Felix。您可以通過這些容器,把您的應(yīng)用程序劈分為多個(gè)模塊單元,這樣,您就可以更容易地管理這些模塊單元之間的交叉依賴關(guān)系。OSGi規(guī)范和Servlet規(guī)范及EJB規(guī)范類似,該規(guī)范定義了兩種對象,一是容器對外提供的服務(wù)對
2、象,另一個(gè)是容器和您的應(yīng)用程序之間必須遵守的契約,其中,服務(wù)對象是容器要實(shí)現(xiàn)的。您如果想要在OSGi平臺上進(jìn)行開發(fā),首先,您必須要使用OSGi API來創(chuàng)建您的應(yīng)用,然后將之部署到OSGi容器中。從開發(fā)者的角度看,OSGi具有以下優(yōu)點(diǎn):a) 您可以在不重啟容器的情況下,動態(tài)地安裝、卸載、啟動和停止您的應(yīng)用程序中的不同模塊;b) 對于您應(yīng)用程序中的某一特定模塊,容器可以同時(shí)運(yùn)行該模塊的多個(gè)版本;c) OSGi為開發(fā)嵌入式應(yīng)用、移動應(yīng)用、富互聯(lián)網(wǎng)應(yīng)用(RIA)提供了非常優(yōu)秀的基礎(chǔ)架構(gòu)如果說您使用Servlet容器開發(fā)您的網(wǎng)絡(luò)應(yīng)用,使用EJB容器開發(fā)交易式應(yīng)用,您可能會問,為什么我們還需要另外的容器
3、呢?對這個(gè)問題的簡短回答是,OSIG容器是專門為開發(fā)復(fù)雜的Java應(yīng)用準(zhǔn)備的,在這些應(yīng)用的開發(fā)過程中,您非常需要將這些應(yīng)用分割為一個(gè)個(gè)的模塊。在本系列以后的文章中,我將針對這個(gè)問題進(jìn)行展開并深入回答。1. OSGi在企業(yè)開發(fā)中的應(yīng)用OSGi聯(lián)盟(OSGiAlliance)于1999年3月開始著手制定OSGi規(guī)范,其主要目的就是要制定一套開放式標(biāo)準(zhǔn),以便向局域網(wǎng)及其中的設(shè)備提供可管理的服務(wù);其基本思路是,一旦您在網(wǎng)絡(luò)設(shè)備(如服務(wù)器和嵌入式設(shè)備)上使用了OSGi服務(wù)平臺,您就可以在網(wǎng)絡(luò)上的任何地方管理這些設(shè)備上運(yùn)行的軟件組件的生命周期,可以在后臺對這些組件進(jìn)行安裝、升級或卸載,但不需要打斷該設(shè)備的
4、正常運(yùn)行。近年來,OSGi技術(shù)在嵌入式系統(tǒng)及網(wǎng)絡(luò)設(shè)備市場得到廣泛應(yīng)用。現(xiàn)在,由于Eclipse的成功,OSGi在企業(yè)開發(fā)中逐漸成為切實(shí)可行的、較有價(jià)值的一種技術(shù)。1.1. 業(yè)界對OSGi的支持逐漸上升2003年,Eclipse開發(fā)團(tuán)隊(duì)開始想辦法提高Eclipse工具集的模塊化,以便讓它成為更加動態(tài)的富客戶端平臺。Eclipse團(tuán)隊(duì)最終選中OSGi框架作為其組件的運(yùn)行時(shí)模型,2004年6月發(fā)布的Eclipse3.0就是第一個(gè)基于OSGi平臺的版本?,F(xiàn)在幾乎所有的企業(yè)應(yīng)用服務(wù)器都支持OSGi,Spring也通過一個(gè)叫“OSGi服務(wù)平臺上的Spring動態(tài)模型(亦稱之為OSGiSpring)”的項(xiàng)目
5、來支持OSGi。該項(xiàng)目提供OSGi基礎(chǔ)架構(gòu),以便我們在Spring的企業(yè)開發(fā)中更容易使用OSGi。2. 開放源碼的OSGi容器從企業(yè)開發(fā)者的角度看,OSGi容器的要求很低,您可以很容易地把它嵌入到企業(yè)應(yīng)用中,比如我們在開發(fā)Web應(yīng)用時(shí),我們可以把這個(gè)Web應(yīng)用分為多個(gè)模塊,一個(gè)模塊負(fù)責(zé)視圖層,另一個(gè)模塊負(fù)責(zé)DAO層,第三個(gè)模塊負(fù)責(zé)數(shù)據(jù)訪問層,如果我們使用OSGi容器來管理這些模塊之間的交叉依賴,我們就可以在不用重啟該Web應(yīng)用的前提下,將DAO層從速度較慢的升級到速度較快的DAO。只要您的應(yīng)用和OSGi規(guī)范兼容,您的應(yīng)用就應(yīng)該可以運(yùn)行在任何OSGi容器中,現(xiàn)在比較流行的開放源碼的OSGi容器有
6、以下三種:a) Equinox容器是參照OSGi規(guī)范第4版實(shí)現(xiàn)的,它構(gòu)成了Eclipse IDE的核心模塊化的Java運(yùn)行時(shí);它實(shí)現(xiàn)了OSGi規(guī)范4中規(guī)定的必須強(qiáng)制實(shí)現(xiàn)的功能,同時(shí),它也實(shí)現(xiàn)了OSGi規(guī)范中大部分的可選功能;b) Knoflerfish是OSGi規(guī)范第3版和第4版的開源實(shí)現(xiàn),它實(shí)現(xiàn)了OSGi規(guī)范規(guī)定的必須實(shí)現(xiàn)的功能及部分可選功能;c) Apache的Felix是Apache軟件基金會實(shí)現(xiàn)的OSGi開源容器,至本文截稿時(shí)為止,該容器還沒有和OSGi規(guī)范完全兼容。在本文中,我們將使用Equinox作為我們的OSGi容器。對OSGi是什么的介紹就先到這里,下面的部分將繼續(xù)介紹OSGi
7、的基礎(chǔ)知識。2.OSGi Bundle之Hello World本文介紹如何開發(fā)OSGi Bundle,使用Hello World做為范例。開發(fā)工具為Eclipse,使用容器為Equinox。開發(fā)一個(gè)簡單的Hello World的OSGi Bundle(OSGi綁定包)在OSGi中,軟件是以Bundle的形式發(fā)布的。一個(gè)Bundle由Java類和其它資源構(gòu)成,它可為其它的Bundle提供服務(wù),也可以導(dǎo)入其它Bundle中的Java包;同時(shí),OSGi的Bundle也可以為其所在的設(shè)備提供一些功能。Eclipse為開發(fā)OSGiBundle提供了優(yōu)秀的支持,它不僅提供了向?qū)韯?chuàng)建OSGi Bundle
8、,而且還提供了內(nèi)嵌的Equinox容器,您可以使用該容器執(zhí)行和調(diào)試OSGi插件。請注意每一個(gè)Eclipse插件,從本質(zhì)上說,都是一個(gè)OSGi Bundle,只是這個(gè)OSGiBundle多加了一些Eclipse專用的代碼而已。下面我們來看看如何使用Eclipse開發(fā)一個(gè)簡單的OSGi的HelloWorld Bundle。3.1.新建Bundle1) 在Eclipse中,點(diǎn)擊“File->New->Project”菜單,您將會看到新項(xiàng)目創(chuàng)建對話框;2) 在新項(xiàng)目對話框中,選擇“Plug-inProject(插件項(xiàng)目)”并點(diǎn)擊“Next(下一步)”按鈕,您將看到插件項(xiàng)目對話框;3) 在插
9、件項(xiàng)目對話框中,請鍵入下列值:Project Name(項(xiàng)目名稱):com.javaworld.sample.HelloWorldTarget Platform(目標(biāo)平臺):an OSGiFramework->Standard (OSGi框架->標(biāo)準(zhǔn))4) 對其它的要求輸入值采用缺省值,并點(diǎn)擊“Next(下一步)”按鈕,您將會看到插件上下文對話框;5) 在插件上下文對話框中,請選擇缺省值并點(diǎn)擊“Next(下一步)”按鈕;6) 在模板對話框中,請選擇“Hello OSGiBundle(你好,OSGi包)”模板,然后點(diǎn)擊“Finish(完成)”按鈕完成該項(xiàng)目。Eclipse將花幾秒鐘生
10、成HelloWorld Bundle模板代碼,它將新建兩個(gè)文件:Activator.java和MANIFEST.MF,下面,讓我們看看這兩個(gè)文件:3.1.1. Activator.java文件源代碼清單1.Activator.java1. package com.javaworld.sample.helloworld; 2. importorg.osgi.framework.BundleActivator; 3. importorg.osgi.framework.BundleContext; 4. publicclass Activato
11、r implements BundleActivator 5. public void start(BundleContext context)throws Exception 6. System.out.println("Helloworld"); 7. 8. public void stop(BundleContext context)throws Exception 9. S
12、ystem.out.println("GoodbyeWorld"); 10. 11. 12. 如果您想讓您開發(fā)的Bundle能在其啟動或關(guān)閉時(shí)通知自身,那么您應(yīng)新建一個(gè)類,讓它實(shí)現(xiàn)BundleActivator接口,同時(shí),您還需要遵行下列規(guī)則:這個(gè)實(shí)現(xiàn)了BundleActivator接口的類必須有一個(gè)public的、不帶參數(shù)的構(gòu)造函數(shù),這樣,OSGi框架就能調(diào)用該類的Class.newInstance()方法創(chuàng)建這個(gè)BundleActivator對象;容器將調(diào)用Activator類的start()方法來啟動Bundle,因此,
13、我們可以在start()方法中執(zhí)行一些資源初始化的操作,例如,我們可以在該方法中獲取數(shù)據(jù)庫連接,以備后用。這個(gè)start()方法的唯一參數(shù)是一個(gè)BundleObject對象,Bundles可以通過該對象和OSGi框架通訊,我們可以從該對象中獲取OSGi容器相關(guān)的一些信息;如果某個(gè)Bundle拋出異常,容器將之置為“stopped(已停止)”狀態(tài),此時(shí),這個(gè)Bundle就不能對外提供服務(wù)。如果我們要關(guān)閉一個(gè)Bundle,容器將調(diào)用Activator類中的stop()方法。因此,我們可在stop()方法中執(zhí)行一些資源清理任務(wù),比如釋放數(shù)據(jù)庫連接。一旦Activator類準(zhǔn)備就緒,您就可以通過MAN
14、IFEST.MF文件把該包的合法名稱傳給容器。下面,我們就看看這個(gè)MANIFEST.MF文件。3.1.2. MANIFEST.MF文件該文件是Bundle的部署描述文件,其格式和正常JAR文件包中的MANIFEST.MF文件相同,因此它由一系列的屬性及這些屬性對應(yīng)的值組成,屬性名位于每一行的開頭,我們可以稱其為屬性頭。OSGi規(guī)范規(guī)定,您可以使用屬性頭向容器描述您的Bundle。您的HelloWorld Bundle的MANIFEST.MF文件看起來應(yīng)該如清單2所示:源代碼清單2. Hello World Bundle中的MANIFEST.MF文件1. Manifest-Version:1.0
15、 2. Bundle-ManifestVersion:2 3. Bundle-Name:HelloWorld Plug-in 4. Bundle-SymbolicName:com.javaworld.sample.HelloWorld 5. Bundle-Version:1.0.0 6. Bundle-Activator:com.javaworld.sample.helloworld.Activator 7. Bundle-Vendor:JAVAWORLD 8. Bundle-Localization:pl
16、ugin 9. Import-Package:org.osgi.framework;version="1.3.0" 10. 我們來看看這個(gè)文件中使用的屬性頭:Bundle-ManifestVersion該屬性頭告訴OSGi容器,本Bundle將遵循OSGi規(guī)范,數(shù)值2表示本Bundle和OSGi規(guī)范第4版本兼容;如果該屬性的數(shù)值為1,那么則表示本包和OSGi版本3或更早版本兼容。Bundle-Name該屬性頭為本Bundle定義了一個(gè)簡短的、可以閱讀的名稱;Bundle-SymbolicName這個(gè)屬性頭為本Bundle定義了一個(gè)唯一的、非
17、本地化的名字;當(dāng)您需要從別的Bundles中訪問某一指定的Bundle時(shí),您就要使用這個(gè)名字。Bundle-Version該屬性頭給出了本Bundle的版本號。Bundle-Activator該屬性頭給出了本Bundle中使用的監(jiān)聽器類名字,這個(gè)屬性值是可選的。監(jiān)聽器將對Activator中的start()和stop()方法監(jiān)聽。在程序清單2中,該屬性頭的值為com.javaworld.sample.helloworld.Activator。Bundle-Vendor該屬性頭是對本Bundle發(fā)行商的表述。Bundle-Localization該屬性頭包含了本Bundle的本地化文件所在的位置
18、,我們的HelloWorld Bundle中并沒有本地化文件,但Eclipse IDE仍自動產(chǎn)生這個(gè)屬性頭Import-Package該屬性頭定義了本Bundle中引入的Java包,我將在本文后面的依賴性管理小節(jié)中詳細(xì)講解這個(gè)問題?,F(xiàn)在,HelloWorld Bundle已經(jīng)準(zhǔn)備就緒,讓我們來運(yùn)行并看看它的輸出結(jié)果。3.2. 運(yùn)行Bundle我在前面提到,Eclipse IDE中有一個(gè)內(nèi)嵌的EquinoxOSGi容器,您可以利用它來執(zhí)行或調(diào)試OSGi Bundle。請按照下面步驟執(zhí)行剛才的HelloWorld Bundle:1 ) 單擊RunàRun 菜單(譯者注,在Eclipse3
19、.3中,請單擊RunàOpen Run Diglog菜單);2) Eclipse會打開“Create,manage and run configuration(新建、管理和運(yùn)行配置)”對話框,請雙擊”EquinoxOSGi Framework”按鈕,Eclipse將打開運(yùn)行時(shí)配置對話框;3) 在上面的對話框中,將Name(名稱)輸入框的值改為HelloWorld Bundle;4) 您會注意到在Workspace插件目錄下,有一個(gè)名為com.javaworld.sample.HelloWorld的插件,請選中它;在TargetPlatform(目標(biāo)平臺)下,請確保org.eclips
20、e.osgi插件被選中。您的Run(運(yùn)行)對話框應(yīng)該看起來如圖1所示: 圖1. HelloWorld Bundle的運(yùn)行配置5) 現(xiàn)在,請單擊Run(運(yùn)行)按鈕,您應(yīng)該看到控制臺視圖上打印出“HelloWorld”。其實(shí),Eclipse是在控制臺視圖中打開OSGi控制臺。3.2.1. OSGi控制臺OSGi控制臺是OSGi容器的命令行界面,您可以在這個(gè)控制臺上啟動、停止、安裝、更新和刪除Bundles。在EclipseIDE中,請點(diǎn)擊該控制臺視圖獲得焦點(diǎn),然后按回車鍵,這時(shí)您可以看到OSGi提示符,如圖2所示:(譯者注,在Eclipse3.3中,如果您沒有看到OSGi提示符,請?jiān)趫D1
21、的運(yùn)行配置中,點(diǎn)擊Arguments標(biāo)簽,然后在ProgramArguments(程序參數(shù))輸入框中鍵入“-console”,然后再次運(yùn)行該Bundle)。 圖2. OSGi控制臺和HelloWorldActivator.java下面是幾個(gè)經(jīng)常使用的OSGi命令,您可以使用這些命令與OSGi容器進(jìn)行交互。1. ss: 該命令顯示所有已安裝的Bundles及它們的狀態(tài),它將顯示Bundle ID,Bundle的簡短名稱及Bundle狀態(tài); 2. start< bundleid>: 該命令將啟動一個(gè)Bundle;
22、;3. stop< bundleid>: 該命令將停止一個(gè)Bundle; 4. update< bundleid>: 該命令使用新的JAR文件更新一個(gè)Bundle; 5. install< bundleid>: 該命令將一個(gè)新的Bundle安裝到OSGi容器; 6. uninstall< bundleid>: 從OSGi容器中卸載一個(gè)已安裝的Bundle。 請注意,這些命令是OSGi規(guī)范中規(guī)定的,因此,您可以
23、使用它們和任何OSGi容器交互。 讀到這里,希望您對OSGi Bundle的開發(fā)有了一個(gè)大致的了解。3.OSGi依賴性管理:Bundle訪問域OSGi允許您把您的應(yīng)用程序分成多個(gè)模塊,并能管理這些模塊之間的依賴性。本文介紹了OSGi依賴性管理的概念。OSGi依賴性管理 OSGi允許您把您的應(yīng)用程序分成多個(gè)模塊,并能管理這些模塊之間的依賴性。為了達(dá)到這個(gè)目的,它引入了Bundle訪問域的概念。Bundle中類的缺省訪問范圍只對本Bundle內(nèi)部可見,但對其它任何Bundle都是不可見的;在Bundle內(nèi)部,類的可訪問性遵循Java語言的一般規(guī)范。那么,您如果想要從一個(gè)Bundle中訪問另一個(gè)Bu
24、ndle中的類,您應(yīng)該怎么辦呢?解決方法是將源Bundle中的包導(dǎo)出來,然后把它們導(dǎo)入到目標(biāo)Bundle中。在本小結(jié)中,我們將通過一個(gè)示例程序說明這個(gè)概念。首先,我們新建一個(gè)名com.javaworld.sample.HelloService的Bundle,并從其中導(dǎo)出一個(gè)包,然后將該包導(dǎo)入到我們的com.javaworld.sample.HelloWorld Bundle中。4.1. 導(dǎo)出Java包我們開始新建一個(gè)com.javaworld.sample.HelloServiceBundle,并從其中導(dǎo)出一個(gè)Java包,具體步驟如下:1) 新建com.javaworld.sample.Hel
25、loService Bundle,具體步驟請參見上小節(jié)中新建com.javaworld.sample.HelloWorldBundle的步驟;2) 在HelloService Bundle中,新建一個(gè)com.javaworld.sample.service.HelloService.java接口,其源代碼如清單3所示。源代碼清單3. HelloService.java1. package com.javaworld.sample.service; 2. public interface HelloService 3. publi
26、c String sayHello(); 4. 5. 3) 新建類com.javaworld.sample.service.impl.HelloServiceImpl.java,該類實(shí)現(xiàn)HelloService接口,其源代碼如清單4所示。源代碼清單4. HelloServiceImpl.java1. package com.javaworld.sample.service.impl; 2. import com.javaworld.sample.service.HelloService; 3.
27、public class HelloServiceImpl implements HelloService 4. public StringsayHello() 5. System.out.println("InsideHelloServiceImple.sayHello()"); 6. return"Say Hello" 7. 8. 9. 4) 請?jiān)谀腅clipse Manifest編
28、輯器中打開HelloService包中的MANIFEST.MF文件,點(diǎn)擊“Runtime(運(yùn)行時(shí))” 標(biāo)簽,在“導(dǎo)出包”小節(jié),單擊“Add(添加)”按鈕,并選擇com.javaworld.sample.service包。這時(shí),HelloServiceBundle中的MANIFEST.MF文件代碼應(yīng)如源代碼清單5所示。源代碼清單5. HelloService Bundle中的Manifest文件1. Manifest-Version: 1.0 2. Bundle-ManifestVersion: 2 3. Bundle-Name: HelloSe
29、rvice Plug-in 4. Bundle-SymbolicName:com.javaworld.sample.HelloService 5. Bundle-Version: 1.0.0 6. Bundle-Vendor: JAVAWORLD 7. Bundle-Localization: plugin 8. Export-Package: com.javaworld.sample.service 9. Import-Package:org.osgi.framework;
30、version="1.3.0" 10. 您可以看到,HelloService Bundle中的MANIFEST.MF文件和HelloWorldBundle非常相似,唯一的區(qū)別就是多了一個(gè)Export-Package屬性頭,該屬性頭的值為com.javaworld.sample.service;Export-Package屬性頭通知OSGi容器,其它Bundle可以從HelloService Bundle外面訪問com.javaworld.sample.service包中的類。請注意,在示例代碼中,我們只暴露了接口類HelloService,而沒有暴露其
31、實(shí)現(xiàn)類的HelloServiceImpl。4.2. 導(dǎo)入Java包下面,我們將從HelloServiceBundle中導(dǎo)出的com.javaworld.sample.service包并將其導(dǎo)入到HelloWorldBundle中,具體步驟如下:1). 請?jiān)赾om.javaworld.sample.HelloWorld Bundle中找到MANIFEST.MF文件,并在Manifest編輯器中打開,點(diǎn)擊“Dependencies(依賴性)”標(biāo)簽,然后點(diǎn)擊“ImportPackage(導(dǎo)入包)”按鈕,將com.javaworld.sample.service添加為導(dǎo)入包,這時(shí),您的HelloWor
32、ldBundle中的MANIFEST.MF文件內(nèi)容應(yīng)如源代碼清單6所示:源代碼清單6. HelloWorld Bundle中的MANIFEST.MF文件1. Manifest-Version: 1.0 2. Bundle-ManifestVersion: 2 3. Bundle-Name: HelloWorld Plug-in 4. Bundle-SymbolicName: com.javaworld.sample.HelloWorld 5. Bundle-Version: 1.0.0
33、60;6. Bundle-Activator: com.javaworld.sample.helloworld.Activator 7. Bundle-Vendor: JAVAWORLD 8. Bundle-Localization: plugin 9. Import-Package: com.javaworld.sample.service, 10. org.osgi.framework;version="1.3.0" 11. 從上面的代碼可以看出,Import-
34、Package屬性頭的值是一個(gè)由逗號分隔的字符串,這是您想導(dǎo)入包的列表。在HelloWorldBundle示例代碼中,我們引入了兩個(gè)包,即com.javaworld.sample.service和org.osgi.framework。org.osgi.framework包中包含有OSGi框架類,比如,在HelloWorldBundle中的Activator.java中用到的BundleContext和BundleActivator類都屬于這個(gè)包。2) 下面,請?jiān)贓clipse Java編輯器中打開com.javaworld.sample.helloworld.Activator.java,您會
35、注意到,您現(xiàn)在可以訪問HelloService接口,但不能訪問HelloServiceImpl實(shí)現(xiàn)類,這是因?yàn)镠elloServiceBunlde只導(dǎo)出了com.javaworld.sampel.service包,同時(shí)HelloWorldBundle也導(dǎo)入了這個(gè)包。HelloServiceImpl是HelloServiceBundle的一個(gè)內(nèi)部類,任何其它的Bundle都不能訪問它。4.3. 類級別上的訪問域如果您運(yùn)行示例的HelloService服務(wù)包,它會在Eclipse控制臺上打印出”HelloWorld”。但是,如果您想在HelloWorld Bundle的Activator中訪問He
36、lloServiceImpl類,這時(shí),編譯沒有問題,但在OSGi容器中運(yùn)行這個(gè)Bundle時(shí)會拋出異常。OSGi容器是如何能將jar文件中的一些類隱藏掉,而讓另外一些類可見呢?這是因?yàn)镺SGi容器使用Java類加載器來管理類的可見性,OSGi容器為每個(gè)Bundle創(chuàng)建不同的類加載器,因此每個(gè)Bundle能訪問位于下列位置中的類:a) 位于Java啟動類路徑下的、所有以Java.*開頭的包中的類;b) 位于OSGi框架類路徑下的類,通常有一個(gè)獨(dú)立的類加載器負(fù)責(zé)加載框架的實(shí)現(xiàn)類及關(guān)鍵的接口類;c) 位于Bundle空間中的類,這些類通常包含在與Bundle相關(guān)的jar文件中,以及加到這個(gè)Bundl
37、e中的其它jar包中的類。d) 導(dǎo)入包中的類,例如,HelloWorld Bundle導(dǎo)入了com.javaworld.sample.service包,因此它能訪問該包中的類。Bundle級別的訪問域是OSGi一個(gè)非常強(qiáng)大的功能,例如,它可以讓您安全地更新HelloServiceImpl.java類,而不必?fù)?dān)心依賴于這個(gè)類的代碼受到破壞。以上就大概介紹了OSGi依賴性管理的概念。4.OSGi服務(wù):非常適合SOA的架構(gòu)本文介紹OSGi服務(wù)。OSGi架構(gòu)非常適合我們實(shí)現(xiàn)面向服務(wù)的應(yīng)用(SOA)。OSGi具有隱藏真實(shí)的服務(wù)實(shí)現(xiàn)類的能力,所以它為面向服務(wù)的應(yīng)用提供了良好的類與接口的組合。OSGi服務(wù)前
38、面我們提到,OSGi架構(gòu)非常適合我們實(shí)現(xiàn)面向服務(wù)的應(yīng)用(SOA)。它可以讓Bundles導(dǎo)出服務(wù),而其它的Bundles可以在不必了解源Bundles任何信息的情況下消費(fèi)這些導(dǎo)出的服務(wù)。由于OSGi具有隱藏真實(shí)的服務(wù)實(shí)現(xiàn)類的能力,所以它為面向服務(wù)的應(yīng)用提供了良好的類與接口的組合。在OSGi框架中,源Bundle在OSGi容器中注冊POJO對象,該對象不必實(shí)現(xiàn)任何接口,也不用繼承任何超類,但它可以注冊在一個(gè)或多個(gè)接口下,并對外提供服務(wù)。目標(biāo)Bundle可以向OSGi容器請求注冊在某一接口下的服務(wù),一旦它發(fā)現(xiàn)該服務(wù),目標(biāo)Bundle就會將該服務(wù)綁定到這個(gè)接口,并能調(diào)用該接口中的方法。下面我們舉個(gè)例
39、子,以便我們能更好理解與OSGi相關(guān)的這些概念。5.1. 導(dǎo)出服務(wù)在本小節(jié)中,我們將更新HelloService Bundle,以便它能把HelloServiceImpl類的對象導(dǎo)出為服務(wù),具體步驟如下:1) 修改com.javaworld.sample.HelloService Bundle中的MANIFEST.MF文件,讓它導(dǎo)入org.osgi.framework包(譯者注,這一步我們已經(jīng)完成);2) 新建Java類com.javaworld.sample.impl.HelloServiceActivator.java,其源代碼如清單7所示;源代碼清單7. HelloServiceActi
40、vator.java1. public class HelloServiceActivator implements BundleActivator 2. ServiceRegistrationhelloServiceRegistration; 3. public void start(BundleContext context)throws Exception 4. HelloService helloService = n
41、ewHelloServiceImpl(); 5. helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null); 6. 7. public void stop(BundleContext context)throws Exception 8. helloServiceRegistration.unregister(); 9.
42、160;10. 11. 請注意,在源Bundle中,我們應(yīng)使用BundleContext.registerService()方法導(dǎo)出服務(wù),這個(gè)方法帶三個(gè)參數(shù):a) 該方法第一個(gè)參數(shù)為您要注冊的服務(wù)的接口名稱。如果您想把您的服務(wù)注冊到多個(gè)接口下,您需要新建一個(gè)String數(shù)組存放這些接口名,然后把這個(gè)數(shù)組作為第一個(gè)參數(shù)傳給registerService()方法。在示例代碼中,我們想把我們的服務(wù)導(dǎo)出到HelloServer接口名下;b) 第二個(gè)參數(shù)是您要注冊的服務(wù)的實(shí)際Java對象。在示例代碼中,我們導(dǎo)出HelloServiceImpl類的對象,并將其作為服務(wù);c) 第三個(gè)
43、參數(shù)為服務(wù)的屬性,它是一個(gè)Dictionary對象。如果多個(gè)Bundle導(dǎo)出服務(wù)的接口名相同,目標(biāo)Bundle就可以使用這些屬性對源Bundle進(jìn)行過濾,找到它感興趣的服務(wù)。3) 最后,請修改HelloServiceBundle中的MANIFEST.MF文件,將Bundle-Activator屬性頭的值改為com.javaworld.sample.service.impl.HelloServiceActivator?,F(xiàn)在HelloService Bundle就可以導(dǎo)出HelloServiceImpl對象了。當(dāng)OSGi容器啟動HelloServiceBundle時(shí),它會將控制權(quán)交給HelloSe
44、rviceActivator.java類,HelloServiceActivator將HelloServiceImpl對象注冊為服務(wù)。下面,我們開始創(chuàng)建該服務(wù)的消費(fèi)者。5.2. 導(dǎo)入服務(wù)在本小節(jié)中,我們將修改上面開發(fā)的HelloWorld Bundle,以便讓它成為HelloService服務(wù)的消費(fèi)者。您主要需要修改HelloWorldBundle中的Activator.java代碼,修改后的代碼如源代碼清單8所示:源代碼清單8. HelloWorld Bundle中的Activator.java1. packagecom.javaworld.sample.helloworld;
45、2. 3. importorg.osgi.framework.BundleActivator; 4. importorg.osgi.framework.BundleContext; 5. importorg.osgi.framework.ServiceReference; 6. importcom.javaworld.sample.service.HelloService; 7. 8. publicclass Activator implements BundleActivator
46、 9. ServiceReference helloServiceReference; 10. public void start(BundleContext context)throws Exception 11. System.out.println("HelloWorld!"); 12. helloServiceReference=context.getServiceReference(HelloService.class.getName(); 1
47、3. HelloService helloService=(HelloService)context.getService(helloServiceReference); 14. System.out.println(helloService.sayHello(); 15. 16. 17. public void stop(BundleContext context)throws Exception 18. System.out.println("Goodbye&
48、#160;World!"); 19. context.ungetService(helloServiceReference); 20. 21. 22. 在上面的代碼中,BundleContext.getServiceReference()方法將為注冊在HelloService接口下的服務(wù)返回一個(gè)ServiceReference對象。如果存在多個(gè)HelloService服務(wù),該方法會返回排行最高的服務(wù)(服務(wù)的排行是通過Constants.SERVICE_RANKING屬性指定的)。您一旦獲得ServiceReference對象
49、,您就可以調(diào)用其BundleContext.getService()方法獲取真實(shí)的服務(wù)對象。您可以參照運(yùn)行Bundle的方法運(yùn)行上面的示例應(yīng)用,請點(diǎn)擊“RunàRun”菜單,并確保HelloWorld和HelloService這兩個(gè)Bundle被選中。當(dāng)您啟動HelloServiceBundle時(shí),您會在控制臺上看到“InsideHelloServiceImple.sayHello()”,這個(gè)消息是由HelloServiceImpl.sayHello()方法打印出來的。5.3. 創(chuàng)建服務(wù)工廠在上節(jié)中,我們學(xué)會了如何使用OSGi框架新建一個(gè)Java對象,并把它注冊為一個(gè)服務(wù),然后讓其它
50、的Bundle去消費(fèi)這個(gè)服務(wù)。如果您看一下HelloServiceActivator.start()方法,您會注意到我們在start()方法中新建了HelloServiceImpl類對象,然后將它注冊到HelloService接口名下。這樣注冊后,任何其它的Bundle在請求HelloService服務(wù)時(shí),OSGi容器將返回同一對象。在大多數(shù)情況下,這樣的實(shí)現(xiàn)方法沒有問題。但是,比如說我們要為每一個(gè)Bundle消費(fèi)者返回不同的HelloServiceImpl對象,再比如說,您的服務(wù)對象要提供的服務(wù)為打開一個(gè)數(shù)據(jù)庫連接,但并不是馬上就打開它,而是在真正需要的時(shí)候才打開這個(gè)數(shù)據(jù)庫連接。對這兩種情況
51、,我們的解決方法是,新建一個(gè)類實(shí)現(xiàn)ServiceFactory接口,并把該類的對象注冊為服務(wù),但并不是注冊實(shí)際的服務(wù)對象。一旦您完成這一步,其它Bundle在請求該服務(wù)時(shí),您的ServiceFactory實(shí)現(xiàn)類將接管該請求,ServiceFactory會為每個(gè)Bundle新建一個(gè)服務(wù)對象,并將真實(shí)服務(wù)的創(chuàng)建時(shí)間延遲到有人真正需要該服務(wù)的時(shí)候。下面我們將使用ServiceFactory更新我們上面開發(fā)的com.javaworld.sample.HelloServiceBundle,具體步驟如下:1) 新建工廠 類HelloServiceFactory.java,源代碼如清單9所示。源代碼清單9
52、. HelloServiceFactory.java1. public class HelloServiceFactory implements ServiceFactory 2. private int usageCounter = 0; 3. public Object getService(Bundle bundle,ServiceRegistration registration) 4. System.out.print
53、ln("Create objectof HelloService for " + bundle.getSymbolicName(); 5. usageCounter+; 6. System.out.println("Number ofbundles using service " + usageCounter); 7. HelloService helloService =
54、0;newHelloServiceImpl(); 8. return helloService; 9. 10. public void ungetService(Bundle bundle,ServiceRegistration registration, Object service) 11. System.out.println("Release objectof HelloService for "&
55、#160;+ bundle.getSymbolicName(); 12. usageCounter-; 13. System.out.println("Number ofbundles using service " + usageCounter); 14. 15. 16. 從上面的代碼中,我們可以看到,ServiceFactory接口定義了兩個(gè)方法:a) getService()方法:當(dāng)某個(gè)Bundle第一次使用BundleCont
56、ext.getService(ServiceReference)方法請求一個(gè)服務(wù)對象時(shí),OSGi框架會調(diào)用該方法。在源代碼清單9中,我們用這個(gè)方法為每個(gè)Bundle新建并返回不同的HelloServiceImpl對象,如果這個(gè)對象不是null,OSGi框架會緩存這個(gè)對象。如果同一個(gè)Bundle再次調(diào)用BundleContext.getService(ServiceReference)方法,OSGi將返回同一個(gè)服務(wù)對象。b) ungetService()方法:當(dāng)Bundle釋放服務(wù)時(shí),OSGi容器可以調(diào)用該方法銷毀服務(wù)對象。在源代碼清單9中,我們使用usageCounter變量來跟蹤服務(wù)的使用數(shù)
57、目,并打印出該服務(wù)的客戶端數(shù)量。2) 修改HelloService Bundle中的HelloServiceActivator.java的start()方法,讓它注冊到ServiceFactory接口名下,而不是注冊到HelloService接口。詳細(xì)代碼如清單10所示:源代碼清單10. 修改后的HelloServiceBundle中的HelloServiceActivator.java1. package com.javaworld.sample.service.impl; 2. importorg.osgi.framework.BundleActivator;
58、60;3. importorg.osgi.framework.BundleContext; 4. importorg.osgi.framework.ServiceRegistration; 5. 6. importcom.javaworld.sample.helloservice.HelloServiceFactory; 7. importcom.javaworld.sample.service.HelloService; 8. 9. publicclass HelloServiceActivator
59、implements BundleActivator 10. ServiceRegistrationhelloServiceRegistration; 11. public void start(BundleContext context)throws Exception 12. HelloServiceFactory helloServiceFactory= new HelloServiceFactory(); 13. helloServic
60、eRegistration=context.registerService(HelloService.class.getName(), helloServiceFactory,null); 14. 15. public void stop(BundleContext context)throws Exception 16. helloServiceRegistration.unregister(); 17. 18. 19. 現(xiàn)在,您可以試運(yùn)行示例代碼
61、。您會注意到,當(dāng)HelloWorld Bundle啟動時(shí),服務(wù)計(jì)數(shù)器變?yōu)?;當(dāng)HelloWorldBundle停止時(shí),服務(wù)計(jì)數(shù)器的數(shù)目將變?yōu)?。5.4. 跟蹤服務(wù)在“OSGi服務(wù)”小節(jié),您學(xué)會了如何使用服務(wù)的接口名搜索服務(wù)。但如果有多個(gè)Bundle使用同一接口名注冊服務(wù),那會發(fā)生什么呢?這時(shí),OSGi容器將返回排行最高的服務(wù),即,返回注冊時(shí)那個(gè)SERVICE_RANKING屬性值最大的服務(wù)。如果有多個(gè)服務(wù)的排行值相等,那么OSGi容器將返回PID值最小的那個(gè)服務(wù)。但是,如果您的服務(wù)消費(fèi)者需要了解某一接口下的服務(wù)對象何時(shí)注冊、何時(shí)取消注冊,這時(shí),您應(yīng)使用ServiceTracker類。下面,我們
62、看看如何使用服務(wù)跟蹤器來修改我們的示例代碼,具體步驟如下。1) 修改HelloWorldBundle的MANIFEST.MF文件,讓它導(dǎo)入org.osgi.util.tracker包;2) 新建類HelloServiceTracker.java,其源代碼參見清單11。源代碼清單11.HelloServiceTracker.java1. public class HelloServiceTracker extends ServiceTracker 2. 3. public&
63、#160;HelloServiceTracker(BundleContext context) 4. 5. super(context, HelloService.class.getName(),null); 6. 7. 8. 9. public Object addingServ
64、ice(ServiceReference reference) 10. 11. System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle(); 12. 13. ret
65、urn super.addingService(reference); 14. 15. 16. 17. public void removedService(ServiceReference reference, Object service) 18. 19.
66、System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle(); 20. 21. super.removedService(reference, service); 22. 23. 24. 25. 26. 在上面的HelloSerivceTracker類的構(gòu)造函數(shù)中,您可以看到,我們把HelloService接口名傳入其父類中,這相當(dāng)于說,HelloServiceTracker應(yīng)跟蹤注冊到HelloService接口名下的所有服
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 油氣加工設(shè)備優(yōu)化-洞察分析
- 2023年-2024年項(xiàng)目部安全培訓(xùn)考試題及答案綜合卷
- 2024年公司項(xiàng)目部負(fù)責(zé)人安全教育培訓(xùn)試題滿分必刷
- 圖像分割與邊緣檢測研究-洞察分析
- 2023-2024安全培訓(xùn)考試題含完整答案【易錯(cuò)題】
- 2023年-2024年生產(chǎn)經(jīng)營單位安全教育培訓(xùn)試題答案高清版
- 醫(yī)藥品電商合規(guī)經(jīng)營研究-洞察分析
- 數(shù)字游戲與兒童心理成長關(guān)系研究-洞察分析
- 市政道路施工現(xiàn)場維護(hù)措施
- 07 短文填空15篇 -2023-2024學(xué)年八年級下冊期中滿分突破(重慶專用)
- 湖南省湘西州吉首市2023屆九年級上學(xué)期期末素質(zhì)監(jiān)測數(shù)學(xué)試卷(含解析)
- 2023-2024學(xué)年湖北省武漢市東西湖區(qū)三年級(上)期末數(shù)學(xué)試卷
- GB/T 31771-2024家政服務(wù)母嬰護(hù)理服務(wù)質(zhì)量規(guī)范
- 2023-建筑施工技02課件講解
- 期末試卷:福建省廈門市集美區(qū)2021-2022學(xué)年八年級上學(xué)期期末歷史試題(原卷版)
- 美容院2024年度規(guī)劃
- 裝飾裝修巡查記錄表
- 公司安全生產(chǎn)事故隱患內(nèi)部報(bào)告獎(jiǎng)勵(lì)工作制度
- 艾滋病預(yù)防知識講座
- 零售服務(wù)質(zhì)量提升
- 《4 平平安安回家來》 說課稿-2024-2025學(xué)年道德與法治一年級上冊統(tǒng)編版
評論
0/150
提交評論