火龍果軟件-OSGi基礎(chǔ)_第1頁
火龍果軟件-OSGi基礎(chǔ)_第2頁
火龍果軟件-OSGi基礎(chǔ)_第3頁
火龍果軟件-OSGi基礎(chǔ)_第4頁
火龍果軟件-OSGi基礎(chǔ)_第5頁
已閱讀5頁,還剩48頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論