OSGi依賴性管理:Bundle訪問域
本文是《你好,OSGi》系列的第三部分。之前介紹過OSGi是什么,以及OSGi Bundle的使用,下面介紹OSGi依賴性管理。
OSGi依賴性管理
OSGi允許您把您的應(yīng)用程序分成多個(gè)模塊,并能管理這些模塊之間的依賴性。為了達(dá)到這個(gè)目的,它引入了Bundle訪問域的概念。Bundle中類的缺省訪問范圍只對(duì)本Bundle內(nèi)部可見,但對(duì)其它任何Bundle都是不可見的;在Bundle內(nèi)部,類的可訪問性遵循Java語言的一般規(guī)范。那么,您如果想要從一個(gè)Bundle中訪問另一個(gè)Bundle中的類,您應(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.HelloService Bundle,具體步驟請(qǐng)參見上小節(jié)中新建com.javaworld.sample.HelloWorldBundle的步驟;
2) 在HelloService Bundle中,新建一個(gè)com.javaworld.sample.service.HelloService.java接口,其源代碼如清單3所示。
源代碼清單3. HelloService.java
- package com.javaworld.sample.service;
- public interface HelloService {
- public String sayHello();
- }
3) 新建類com.javaworld.sample.service.impl.HelloServiceImpl.java,該類實(shí)現(xiàn)HelloService接口,其源代碼如清單4所示。
源代碼清單4. HelloServiceImpl.java
- package com.javaworld.sample.service.impl;
- import com.javaworld.sample.service.HelloService;
- public class HelloServiceImpl implements HelloService {
- public StringsayHello() {
- System.out.println("InsideHelloServiceImple.sayHello()");
- return"Say Hello";
- }
- }
4) 請(qǐng)?jiān)谀腅clipse Manifest編輯器中打開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文件
- Manifest-Version: 1.0
- Bundle-ManifestVersion: 2
- Bundle-Name: HelloService Plug-in
- Bundle-SymbolicName:com.javaworld.sample.HelloService
- Bundle-Version: 1.0.0
- Bundle-Vendor: JAVAWORLD
- Bundle-Localization: plugin
- Export-Package: com.javaworld.sample.service
- Import-Package:org.osgi.framework;version="1.3.0"
您可以看到,HelloService Bundle中的MANIFEST.MF文件和HelloWorldBundle非常相似,唯一的區(qū)別就是多了一個(gè)Export-Package屬性頭,該屬性頭的值為com.javaworld.sample.service;Export-Package屬性頭通知OSGi容器,其它Bundle可以從HelloService Bundle外面訪問com.javaworld.sample.service包中的類。請(qǐng)注意,在示例代碼中,我們只暴露了接口類HelloService,而沒有暴露其實(shí)現(xiàn)類的HelloServiceImpl。
4.2. 導(dǎo)入Java包
下面,我們將從HelloServiceBundle中導(dǎo)出的com.javaworld.sample.service包并將其導(dǎo)入到HelloWorldBundle中,具體步驟如下:
1). 請(qǐng)?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í),您的HelloWorldBundle中的MANIFEST.MF文件內(nèi)容應(yīng)如源代碼清單6所示:
源代碼清單6. HelloWorld Bundle中的MANIFEST.MF文件
- Manifest-Version: 1.0
- Bundle-ManifestVersion: 2
- Bundle-Name: HelloWorld Plug-in
- Bundle-SymbolicName: com.javaworld.sample.HelloWorld
- Bundle-Version: 1.0.0
- Bundle-Activator: com.javaworld.sample.helloworld.Activator
- Bundle-Vendor: JAVAWORLD
- Bundle-Localization: plugin
- Import-Package: com.javaworld.sample.service,
- org.osgi.framework;version="1.3.0"
從上面的代碼可以看出,Import-Package屬性頭的值是一個(gè)由逗號(hào)分隔的字符串,這是您想導(dǎo)入包的列表。在HelloWorldBundle示例代碼中,我們引入了兩個(gè)包,即com.javaworld.sample.service和org.osgi.framework。
org.osgi.framework包中包含有OSGi框架類,比如,在HelloWorldBundle中的Activator.java中用到的BundleContext和BundleActivator類都屬于這個(gè)包。
2) 下面,請(qǐng)?jiān)贓clipse Java編輯器中打開com.javaworld.sample.helloworld.Activator.java,您會(huì)注意到,您現(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. 類級(jí)別上的訪問域
如果您運(yùn)行示例的HelloService服務(wù)包,它會(huì)在Eclipse控制臺(tái)上打印出”HelloWorld”。但是,如果您想在HelloWorld Bundle的Activator中訪問HelloServiceImpl類,這時(shí),編譯沒有問題,但在OSGi容器中運(yùn)行這個(gè)Bundle時(shí)會(huì)拋出異常。
OSGi容器是如何能將jar文件中的一些類隱藏掉,而讓另外一些類可見呢?這是因?yàn)镺SGi容器使用Java類加載器來管理類的可見性,OSGi容器為每個(gè)Bundle創(chuàng)建不同的類加載器,因此每個(gè)Bundle能訪問位于下列位置中的類:
a) 位于Java啟動(dòng)類路徑下的、所有以Java.*開頭的包中的類;
b) 位于OSGi框架類路徑下的類,通常有一個(gè)獨(dú)立的類加載器負(fù)責(zé)加載框架的實(shí)現(xiàn)類及關(guān)鍵的接口類;
c) 位于Bundle空間中的類,這些類通常包含在與Bundle相關(guān)的jar文件中,以及加到這個(gè)Bundle中的其它jar包中的類。
d) 導(dǎo)入包中的類,例如,HelloWorld Bundle導(dǎo)入了com.javaworld.sample.service包,因此它能訪問該包中的類。Bundle級(jí)別的訪問域是OSGi一個(gè)非常強(qiáng)大的功能,例如,它可以讓您安全地更新HelloServiceImpl.java類,而不必?fù)?dān)心依賴于這個(gè)類的代碼受到破壞。
以上就大概介紹了OSGi依賴性管理的概念。
【編輯推薦】