




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、 火龍果整理 1.OSGi是什么:Java語言的動態模塊系統本文介紹了OSGi是什么,以及OSGi容器的一些現狀。OSGi亦稱做Java語言的動態模塊系統,它為模塊化應用的開發定義了一個基礎架構。OSGi是什么OSGi亦稱做Java語言的動態模塊系統,它為模塊化應用的開發定義了一個基礎架構。OSGi容器已有多家開源實現,比如Knoflerfish、Equinox和Apache的Felix。您可以通過這些容器,把您的應用程序劈分為多個模塊單元,這樣,您就可以更容易地管理這些模塊單元之間的交叉依賴關系。OSGi規范和Servlet規范及EJB規范類似,該規范定義了兩種對象,一是容器對外提供的服務對
2、象,另一個是容器和您的應用程序之間必須遵守的契約,其中,服務對象是容器要實現的。您如果想要在OSGi平臺上進行開發,首先,您必須要使用OSGi API來創建您的應用,然后將之部署到OSGi容器中。從開發者的角度看,OSGi具有以下優點:a) 您可以在不重啟容器的情況下,動態地安裝、卸載、啟動和停止您的應用程序中的不同模塊;b) 對于您應用程序中的某一特定模塊,容器可以同時運行該模塊的多個版本;c) OSGi為開發嵌入式應用、移動應用、富互聯網應用(RIA)提供了非常優秀的基礎架構如果說您使用Servlet容器開發您的網絡應用,使用EJB容器開發交易式應用,您可能會問,為什么我們還需要另外的容器
3、呢?對這個問題的簡短回答是,OSIG容器是專門為開發復雜的Java應用準備的,在這些應用的開發過程中,您非常需要將這些應用分割為一個個的模塊。在本系列以后的文章中,我將針對這個問題進行展開并深入回答。1. OSGi在企業開發中的應用OSGi聯盟(OSGiAlliance)于1999年3月開始著手制定OSGi規范,其主要目的就是要制定一套開放式標準,以便向局域網及其中的設備提供可管理的服務;其基本思路是,一旦您在網絡設備(如服務器和嵌入式設備)上使用了OSGi服務平臺,您就可以在網絡上的任何地方管理這些設備上運行的軟件組件的生命周期,可以在后臺對這些組件進行安裝、升級或卸載,但不需要打斷該設備的
4、正常運行。近年來,OSGi技術在嵌入式系統及網絡設備市場得到廣泛應用。現在,由于Eclipse的成功,OSGi在企業開發中逐漸成為切實可行的、較有價值的一種技術。1.1. 業界對OSGi的支持逐漸上升2003年,Eclipse開發團隊開始想辦法提高Eclipse工具集的模塊化,以便讓它成為更加動態的富客戶端平臺。Eclipse團隊最終選中OSGi框架作為其組件的運行時模型,2004年6月發布的Eclipse3.0就是第一個基于OSGi平臺的版本。現在幾乎所有的企業應用服務器都支持OSGi,Spring也通過一個叫“OSGi服務平臺上的Spring動態模型(亦稱之為OSGiSpring)”的項目
5、來支持OSGi。該項目提供OSGi基礎架構,以便我們在Spring的企業開發中更容易使用OSGi。2. 開放源碼的OSGi容器從企業開發者的角度看,OSGi容器的要求很低,您可以很容易地把它嵌入到企業應用中,比如我們在開發Web應用時,我們可以把這個Web應用分為多個模塊,一個模塊負責視圖層,另一個模塊負責DAO層,第三個模塊負責數據訪問層,如果我們使用OSGi容器來管理這些模塊之間的交叉依賴,我們就可以在不用重啟該Web應用的前提下,將DAO層從速度較慢的升級到速度較快的DAO。只要您的應用和OSGi規范兼容,您的應用就應該可以運行在任何OSGi容器中,現在比較流行的開放源碼的OSGi容器有
6、以下三種:a) Equinox容器是參照OSGi規范第4版實現的,它構成了Eclipse IDE的核心模塊化的Java運行時;它實現了OSGi規范4中規定的必須強制實現的功能,同時,它也實現了OSGi規范中大部分的可選功能;b) Knoflerfish是OSGi規范第3版和第4版的開源實現,它實現了OSGi規范規定的必須實現的功能及部分可選功能;c) Apache的Felix是Apache軟件基金會實現的OSGi開源容器,至本文截稿時為止,該容器還沒有和OSGi規范完全兼容。在本文中,我們將使用Equinox作為我們的OSGi容器。對OSGi是什么的介紹就先到這里,下面的部分將繼續介紹OSGi
7、的基礎知識。2.OSGi Bundle之Hello World本文介紹如何開發OSGi Bundle,使用Hello World做為范例。開發工具為Eclipse,使用容器為Equinox。開發一個簡單的Hello World的OSGi Bundle(OSGi綁定包)在OSGi中,軟件是以Bundle的形式發布的。一個Bundle由Java類和其它資源構成,它可為其它的Bundle提供服務,也可以導入其它Bundle中的Java包;同時,OSGi的Bundle也可以為其所在的設備提供一些功能。Eclipse為開發OSGiBundle提供了優秀的支持,它不僅提供了向導來創建OSGi Bundle
8、,而且還提供了內嵌的Equinox容器,您可以使用該容器執行和調試OSGi插件。請注意每一個Eclipse插件,從本質上說,都是一個OSGi Bundle,只是這個OSGiBundle多加了一些Eclipse專用的代碼而已。下面我們來看看如何使用Eclipse開發一個簡單的OSGi的HelloWorld Bundle。3.1.新建Bundle1) 在Eclipse中,點擊“File->New->Project”菜單,您將會看到新項目創建對話框;2) 在新項目對話框中,選擇“Plug-inProject(插件項目)”并點擊“Next(下一步)”按鈕,您將看到插件項目對話框;3) 在插
9、件項目對話框中,請鍵入下列值:Project Name(項目名稱):com.javaworld.sample.HelloWorldTarget Platform(目標平臺):an OSGiFramework->Standard (OSGi框架->標準)4) 對其它的要求輸入值采用缺省值,并點擊“Next(下一步)”按鈕,您將會看到插件上下文對話框;5) 在插件上下文對話框中,請選擇缺省值并點擊“Next(下一步)”按鈕;6) 在模板對話框中,請選擇“Hello OSGiBundle(你好,OSGi包)”模板,然后點擊“Finish(完成)”按鈕完成該項目。Eclipse將花幾秒鐘生
10、成HelloWorld Bundle模板代碼,它將新建兩個文件:Activator.java和MANIFEST.MF,下面,讓我們看看這兩個文件: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. 如果您想讓您開發的Bundle能在其啟動或關閉時通知自身,那么您應新建一個類,讓它實現BundleActivator接口,同時,您還需要遵行下列規則:這個實現了BundleActivator接口的類必須有一個public的、不帶參數的構造函數,這樣,OSGi框架就能調用該類的Class.newInstance()方法創建這個BundleActivator對象;容器將調用Activator類的start()方法來啟動Bundle,因此,
13、我們可以在start()方法中執行一些資源初始化的操作,例如,我們可以在該方法中獲取數據庫連接,以備后用。這個start()方法的唯一參數是一個BundleObject對象,Bundles可以通過該對象和OSGi框架通訊,我們可以從該對象中獲取OSGi容器相關的一些信息;如果某個Bundle拋出異常,容器將之置為“stopped(已停止)”狀態,此時,這個Bundle就不能對外提供服務。如果我們要關閉一個Bundle,容器將調用Activator類中的stop()方法。因此,我們可在stop()方法中執行一些資源清理任務,比如釋放數據庫連接。一旦Activator類準備就緒,您就可以通過MAN
14、IFEST.MF文件把該包的合法名稱傳給容器。下面,我們就看看這個MANIFEST.MF文件。3.1.2. MANIFEST.MF文件該文件是Bundle的部署描述文件,其格式和正常JAR文件包中的MANIFEST.MF文件相同,因此它由一系列的屬性及這些屬性對應的值組成,屬性名位于每一行的開頭,我們可以稱其為屬性頭。OSGi規范規定,您可以使用屬性頭向容器描述您的Bundle。您的HelloWorld Bundle的MANIFEST.MF文件看起來應該如清單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. 我們來看看這個文件中使用的屬性頭:Bundle-ManifestVersion該屬性頭告訴OSGi容器,本Bundle將遵循OSGi規范,數值2表示本Bundle和OSGi規范第4版本兼容;如果該屬性的數值為1,那么則表示本包和OSGi版本3或更早版本兼容。Bundle-Name該屬性頭為本Bundle定義了一個簡短的、可以閱讀的名稱;Bundle-SymbolicName這個屬性頭為本Bundle定義了一個唯一的、非
17、本地化的名字;當您需要從別的Bundles中訪問某一指定的Bundle時,您就要使用這個名字。Bundle-Version該屬性頭給出了本Bundle的版本號。Bundle-Activator該屬性頭給出了本Bundle中使用的監聽器類名字,這個屬性值是可選的。監聽器將對Activator中的start()和stop()方法監聽。在程序清單2中,該屬性頭的值為com.javaworld.sample.helloworld.Activator。Bundle-Vendor該屬性頭是對本Bundle發行商的表述。Bundle-Localization該屬性頭包含了本Bundle的本地化文件所在的位置
18、,我們的HelloWorld Bundle中并沒有本地化文件,但Eclipse IDE仍自動產生這個屬性頭Import-Package該屬性頭定義了本Bundle中引入的Java包,我將在本文后面的依賴性管理小節中詳細講解這個問題。現在,HelloWorld Bundle已經準備就緒,讓我們來運行并看看它的輸出結果。3.2. 運行Bundle我在前面提到,Eclipse IDE中有一個內嵌的EquinoxOSGi容器,您可以利用它來執行或調試OSGi Bundle。請按照下面步驟執行剛才的HelloWorld Bundle:1 ) 單擊RunàRun 菜單(譯者注,在Eclipse3
19、.3中,請單擊RunàOpen Run Diglog菜單);2) Eclipse會打開“Create,manage and run configuration(新建、管理和運行配置)”對話框,請雙擊”EquinoxOSGi Framework”按鈕,Eclipse將打開運行時配置對話框;3) 在上面的對話框中,將Name(名稱)輸入框的值改為HelloWorld Bundle;4) 您會注意到在Workspace插件目錄下,有一個名為com.javaworld.sample.HelloWorld的插件,請選中它;在TargetPlatform(目標平臺)下,請確保org.eclips
20、e.osgi插件被選中。您的Run(運行)對話框應該看起來如圖1所示: 圖1. HelloWorld Bundle的運行配置5) 現在,請單擊Run(運行)按鈕,您應該看到控制臺視圖上打印出“HelloWorld”。其實,Eclipse是在控制臺視圖中打開OSGi控制臺。3.2.1. OSGi控制臺OSGi控制臺是OSGi容器的命令行界面,您可以在這個控制臺上啟動、停止、安裝、更新和刪除Bundles。在EclipseIDE中,請點擊該控制臺視圖獲得焦點,然后按回車鍵,這時您可以看到OSGi提示符,如圖2所示:(譯者注,在Eclipse3.3中,如果您沒有看到OSGi提示符,請在圖1
21、的運行配置中,點擊Arguments標簽,然后在ProgramArguments(程序參數)輸入框中鍵入“-console”,然后再次運行該Bundle)。 圖2. OSGi控制臺和HelloWorldActivator.java下面是幾個經常使用的OSGi命令,您可以使用這些命令與OSGi容器進行交互。1. ss: 該命令顯示所有已安裝的Bundles及它們的狀態,它將顯示Bundle ID,Bundle的簡短名稱及Bundle狀態; 2. start< bundleid>: 該命令將啟動一個Bundle;
22、;3. stop< bundleid>: 該命令將停止一個Bundle; 4. update< bundleid>: 該命令使用新的JAR文件更新一個Bundle; 5. install< bundleid>: 該命令將一個新的Bundle安裝到OSGi容器; 6. uninstall< bundleid>: 從OSGi容器中卸載一個已安裝的Bundle。 請注意,這些命令是OSGi規范中規定的,因此,您可以
23、使用它們和任何OSGi容器交互。 讀到這里,希望您對OSGi Bundle的開發有了一個大致的了解。3.OSGi依賴性管理:Bundle訪問域OSGi允許您把您的應用程序分成多個模塊,并能管理這些模塊之間的依賴性。本文介紹了OSGi依賴性管理的概念。OSGi依賴性管理 OSGi允許您把您的應用程序分成多個模塊,并能管理這些模塊之間的依賴性。為了達到這個目的,它引入了Bundle訪問域的概念。Bundle中類的缺省訪問范圍只對本Bundle內部可見,但對其它任何Bundle都是不可見的;在Bundle內部,類的可訪問性遵循Java語言的一般規范。那么,您如果想要從一個Bundle中訪問另一個Bu
24、ndle中的類,您應該怎么辦呢?解決方法是將源Bundle中的包導出來,然后把它們導入到目標Bundle中。在本小結中,我們將通過一個示例程序說明這個概念。首先,我們新建一個名com.javaworld.sample.HelloService的Bundle,并從其中導出一個包,然后將該包導入到我們的com.javaworld.sample.HelloWorld Bundle中。4.1. 導出Java包我們開始新建一個com.javaworld.sample.HelloServiceBundle,并從其中導出一個Java包,具體步驟如下:1) 新建com.javaworld.sample.Hel
25、loService Bundle,具體步驟請參見上小節中新建com.javaworld.sample.HelloWorldBundle的步驟;2) 在HelloService Bundle中,新建一個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,該類實現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) 請在您的Eclipse Manifest編
28、輯器中打開HelloService包中的MANIFEST.MF文件,點擊“Runtime(運行時)” 標簽,在“導出包”小節,單擊“Add(添加)”按鈕,并選擇com.javaworld.sample.service包。這時,HelloServiceBundle中的MANIFEST.MF文件代碼應如源代碼清單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非常相似,唯一的區別就是多了一個Export-Package屬性頭,該屬性頭的值為com.javaworld.sample.service;Export-Package屬性頭通知OSGi容器,其它Bundle可以從HelloService Bundle外面訪問com.javaworld.sample.service包中的類。請注意,在示例代碼中,我們只暴露了接口類HelloService,而沒有暴露其
31、實現類的HelloServiceImpl。4.2. 導入Java包下面,我們將從HelloServiceBundle中導出的com.javaworld.sample.service包并將其導入到HelloWorldBundle中,具體步驟如下:1). 請在com.javaworld.sample.HelloWorld Bundle中找到MANIFEST.MF文件,并在Manifest編輯器中打開,點擊“Dependencies(依賴性)”標簽,然后點擊“ImportPackage(導入包)”按鈕,將com.javaworld.sample.service添加為導入包,這時,您的HelloWor
32、ldBundle中的MANIFEST.MF文件內容應如源代碼清單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屬性頭的值是一個由逗號分隔的字符串,這是您想導入包的列表。在HelloWorldBundle示例代碼中,我們引入了兩個包,即com.javaworld.sample.service和org.osgi.framework。org.osgi.framework包中包含有OSGi框架類,比如,在HelloWorldBundle中的Activator.java中用到的BundleContext和BundleActivator類都屬于這個包。2) 下面,請在Eclipse Java編輯器中打開com.javaworld.sample.helloworld.Activator.java,您會
35、注意到,您現在可以訪問HelloService接口,但不能訪問HelloServiceImpl實現類,這是因為HelloServiceBunlde只導出了com.javaworld.sampel.service包,同時HelloWorldBundle也導入了這個包。HelloServiceImpl是HelloServiceBundle的一個內部類,任何其它的Bundle都不能訪問它。4.3. 類級別上的訪問域如果您運行示例的HelloService服務包,它會在Eclipse控制臺上打印出”HelloWorld”。但是,如果您想在HelloWorld Bundle的Activator中訪問He
36、lloServiceImpl類,這時,編譯沒有問題,但在OSGi容器中運行這個Bundle時會拋出異常。OSGi容器是如何能將jar文件中的一些類隱藏掉,而讓另外一些類可見呢?這是因為OSGi容器使用Java類加載器來管理類的可見性,OSGi容器為每個Bundle創建不同的類加載器,因此每個Bundle能訪問位于下列位置中的類:a) 位于Java啟動類路徑下的、所有以Java.*開頭的包中的類;b) 位于OSGi框架類路徑下的類,通常有一個獨立的類加載器負責加載框架的實現類及關鍵的接口類;c) 位于Bundle空間中的類,這些類通常包含在與Bundle相關的jar文件中,以及加到這個Bundl
37、e中的其它jar包中的類。d) 導入包中的類,例如,HelloWorld Bundle導入了com.javaworld.sample.service包,因此它能訪問該包中的類。Bundle級別的訪問域是OSGi一個非常強大的功能,例如,它可以讓您安全地更新HelloServiceImpl.java類,而不必擔心依賴于這個類的代碼受到破壞。以上就大概介紹了OSGi依賴性管理的概念。4.OSGi服務:非常適合SOA的架構本文介紹OSGi服務。OSGi架構非常適合我們實現面向服務的應用(SOA)。OSGi具有隱藏真實的服務實現類的能力,所以它為面向服務的應用提供了良好的類與接口的組合。OSGi服務前
38、面我們提到,OSGi架構非常適合我們實現面向服務的應用(SOA)。它可以讓Bundles導出服務,而其它的Bundles可以在不必了解源Bundles任何信息的情況下消費這些導出的服務。由于OSGi具有隱藏真實的服務實現類的能力,所以它為面向服務的應用提供了良好的類與接口的組合。在OSGi框架中,源Bundle在OSGi容器中注冊POJO對象,該對象不必實現任何接口,也不用繼承任何超類,但它可以注冊在一個或多個接口下,并對外提供服務。目標Bundle可以向OSGi容器請求注冊在某一接口下的服務,一旦它發現該服務,目標Bundle就會將該服務綁定到這個接口,并能調用該接口中的方法。下面我們舉個例
39、子,以便我們能更好理解與OSGi相關的這些概念。5.1. 導出服務在本小節中,我們將更新HelloService Bundle,以便它能把HelloServiceImpl類的對象導出為服務,具體步驟如下:1) 修改com.javaworld.sample.HelloService Bundle中的MANIFEST.MF文件,讓它導入org.osgi.framework包(譯者注,這一步我們已經完成);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中,我們應使用BundleContext.registerService()方法導出服務,這個方法帶三個參數:a) 該方法第一個參數為您要注冊的服務的接口名稱。如果您想把您的服務注冊到多個接口下,您需要新建一個String數組存放這些接口名,然后把這個數組作為第一個參數傳給registerService()方法。在示例代碼中,我們想把我們的服務導出到HelloServer接口名下;b) 第二個參數是您要注冊的服務的實際Java對象。在示例代碼中,我們導出HelloServiceImpl類的對象,并將其作為服務;c) 第三個
43、參數為服務的屬性,它是一個Dictionary對象。如果多個Bundle導出服務的接口名相同,目標Bundle就可以使用這些屬性對源Bundle進行過濾,找到它感興趣的服務。3) 最后,請修改HelloServiceBundle中的MANIFEST.MF文件,將Bundle-Activator屬性頭的值改為com.javaworld.sample.service.impl.HelloServiceActivator。現在HelloService Bundle就可以導出HelloServiceImpl對象了。當OSGi容器啟動HelloServiceBundle時,它會將控制權交給HelloSe
44、rviceActivator.java類,HelloServiceActivator將HelloServiceImpl對象注冊為服務。下面,我們開始創建該服務的消費者。5.2. 導入服務在本小節中,我們將修改上面開發的HelloWorld Bundle,以便讓它成為HelloService服務的消費者。您主要需要修改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接口下的服務返回一個ServiceReference對象。如果存在多個HelloService服務,該方法會返回排行最高的服務(服務的排行是通過Constants.SERVICE_RANKING屬性指定的)。您一旦獲得ServiceReference對象
49、,您就可以調用其BundleContext.getService()方法獲取真實的服務對象。您可以參照運行Bundle的方法運行上面的示例應用,請點擊“RunàRun”菜單,并確保HelloWorld和HelloService這兩個Bundle被選中。當您啟動HelloServiceBundle時,您會在控制臺上看到“InsideHelloServiceImple.sayHello()”,這個消息是由HelloServiceImpl.sayHello()方法打印出來的。5.3. 創建服務工廠在上節中,我們學會了如何使用OSGi框架新建一個Java對象,并把它注冊為一個服務,然后讓其它
50、的Bundle去消費這個服務。如果您看一下HelloServiceActivator.start()方法,您會注意到我們在start()方法中新建了HelloServiceImpl類對象,然后將它注冊到HelloService接口名下。這樣注冊后,任何其它的Bundle在請求HelloService服務時,OSGi容器將返回同一對象。在大多數情況下,這樣的實現方法沒有問題。但是,比如說我們要為每一個Bundle消費者返回不同的HelloServiceImpl對象,再比如說,您的服務對象要提供的服務為打開一個數據庫連接,但并不是馬上就打開它,而是在真正需要的時候才打開這個數據庫連接。對這兩種情況
51、,我們的解決方法是,新建一個類實現ServiceFactory接口,并把該類的對象注冊為服務,但并不是注冊實際的服務對象。一旦您完成這一步,其它Bundle在請求該服務時,您的ServiceFactory實現類將接管該請求,ServiceFactory會為每個Bundle新建一個服務對象,并將真實服務的創建時間延遲到有人真正需要該服務的時候。下面我們將使用ServiceFactory更新我們上面開發的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接口定義了兩個方法:a) getService()方法:當某個Bundle第一次使用BundleCont
56、ext.getService(ServiceReference)方法請求一個服務對象時,OSGi框架會調用該方法。在源代碼清單9中,我們用這個方法為每個Bundle新建并返回不同的HelloServiceImpl對象,如果這個對象不是null,OSGi框架會緩存這個對象。如果同一個Bundle再次調用BundleContext.getService(ServiceReference)方法,OSGi將返回同一個服務對象。b) ungetService()方法:當Bundle釋放服務時,OSGi容器可以調用該方法銷毀服務對象。在源代碼清單9中,我們使用usageCounter變量來跟蹤服務的使用數
57、目,并打印出該服務的客戶端數量。2) 修改HelloService Bundle中的HelloServiceActivator.java的start()方法,讓它注冊到ServiceFactory接口名下,而不是注冊到HelloService接口。詳細代碼如清單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. 現在,您可以試運行示例代碼
61、。您會注意到,當HelloWorld Bundle啟動時,服務計數器變為1;當HelloWorldBundle停止時,服務計數器的數目將變為0。5.4. 跟蹤服務在“OSGi服務”小節,您學會了如何使用服務的接口名搜索服務。但如果有多個Bundle使用同一接口名注冊服務,那會發生什么呢?這時,OSGi容器將返回排行最高的服務,即,返回注冊時那個SERVICE_RANKING屬性值最大的服務。如果有多個服務的排行值相等,那么OSGi容器將返回PID值最小的那個服務。但是,如果您的服務消費者需要了解某一接口下的服務對象何時注冊、何時取消注冊,這時,您應使用ServiceTracker類。下面,我們
62、看看如何使用服務跟蹤器來修改我們的示例代碼,具體步驟如下。1) 修改HelloWorldBundle的MANIFEST.MF文件,讓它導入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類的構造函數中,您可以看到,我們把HelloService接口名傳入其父類中,這相當于說,HelloServiceTracker應跟蹤注冊到HelloService接口名下的所有服
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 粵海地理競賽試題及答案
- 沙灘彈唱面試題及答案
- 理解紡織品生產全過程的質量管理試題及答案
- 廣告設計師證書考試創意展示試題及答案
- 科技武器考試題及答案
- 健康領域測試題及答案
- 2024年紡織設計師考點解析試題及答案
- 電話客服考試試題及答案
- 助理廣告師項目執行能力試題及答案
- 2024國際設計師考試心得體會試題及答案
- 標準實施情況報告
- 農業安全問題
- 導管護理相關知識
- 上海2025年上海交通大學醫學院招聘72人筆試歷年參考題庫附帶答案詳解
- DB37-T 5061-2024 住宅小區供配電設施建設標準
- GB/T 45135-2024鈦合金板材超塑成形和擴散連接件通用技術規范
- (2025)時事政治題庫(含參考答案)
- 【含聽力9英一模】合肥市蜀山區2024年中考一模英語
- 保利拍賣行合同模板
- 2025年中國融通農發社會招聘筆試參考題庫含答案解析
- 養老院護理員培訓制度
評論
0/150
提交評論