OSGI使用詳解文檔_第1頁(yè)
OSGI使用詳解文檔_第2頁(yè)
OSGI使用詳解文檔_第3頁(yè)
OSGI使用詳解文檔_第4頁(yè)
OSGI使用詳解文檔_第5頁(yè)
已閱讀5頁(yè),還剩55頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、企業(yè)服務(wù)總線系統(tǒng)(ESB)技術(shù)白皮書OSGI使用編輯人:yglOSGi 是目前動(dòng)態(tài)模塊系統(tǒng)的事實(shí)上的工業(yè)標(biāo)準(zhǔn),雖然一開始只是作為嵌入式設(shè)備和家庭網(wǎng)關(guān)的框架來使用,但是實(shí)際上它適用于任何需要模塊化、面向服務(wù)、面向組件的應(yīng)用程序。而 Equinox 則是的 Eclipse 所使用的 OSGi 框架,是 Eclipse 強(qiáng)大的插件體系的基礎(chǔ),Eclipse 的穩(wěn)定可靠性也為該框架帶來了聲譽(yù)。本文章就將演示如何在 Eclipse 環(huán)境下利用 Equinox 框架進(jìn)行 OSGi 應(yīng)用開發(fā)。首先解釋了實(shí)現(xiàn)上述應(yīng)用程序所必需了解的基本概念和基礎(chǔ)知識(shí),并結(jié)合示例代碼演示 OSGi 開發(fā)的一些重要技術(shù),最后探討

2、了基于 OSGi 應(yīng)用程序一般所采用的架構(gòu),以及如何將 Equinox OSGi 應(yīng)用程序脫離 Eclipse 而部署為一個(gè)標(biāo)準(zhǔn)的 Java 應(yīng)用程序。1 Osgi及框架簡(jiǎn)介1.1 OSGi 簡(jiǎn)介OSGi 是目前動(dòng)態(tài)模塊系統(tǒng)的事實(shí)上的工業(yè)標(biāo)準(zhǔn),雖然一開始只是作為嵌入式設(shè)備和家庭網(wǎng)關(guān)的框架來使用,但是實(shí)際上它適用于任何需要模塊化、面向服務(wù)、面向組件的應(yīng)用程序。目前 OSGi 規(guī)范已經(jīng)發(fā)展到第四版(R4), 由 OSGi 聯(lián)合組織(OSGi Alliance)負(fù)責(zé)進(jìn)行維護(hù)管理,相關(guān)的規(guī)范資料也可以從該網(wǎng)站獲得。1.2 OSGi 框架開發(fā)基于 OSGi 的應(yīng)用程序離不開實(shí)現(xiàn)了 OSGi 標(biāo)準(zhǔn)的框架,

3、就好比是基于 J2EE 的開發(fā)離不開應(yīng)用服務(wù)器一樣。目前比較流行的基于 OSGi R4 標(biāo)準(zhǔn)實(shí)現(xiàn)的 OSGi 框架有三個(gè):Equinox:這是大名鼎鼎的 Eclipse 所使用的 OSGi 框架,Eclipse 強(qiáng)大的插件體系就是構(gòu)建在 OSGi bundles 的基礎(chǔ)之上,Eclipse 的穩(wěn)定可靠性為該框架帶來了聲譽(yù),而且由于有 IBM 公司的強(qiáng)力支持,其后續(xù)的開發(fā)和文檔資料也有了一定的保障。一般情況下,我們推薦您使用該框架進(jìn)行 OSGi 開發(fā)。本教程的后續(xù)部分也將演示如何使用 Equinox 框架來進(jìn)行 OSGi 應(yīng)用程序的開發(fā)。Makewave Knopflerfish:這是另外一個(gè)比

4、較知名的 OSGi 框架,目前的版本已經(jīng)支持 R4 規(guī)范,其特點(diǎn)在于為應(yīng)用程序的開發(fā)提供了大量的 bundle 。Apache Flex:由 Apache 基金組織開發(fā)的面向社區(qū)的 OSGi 框架實(shí)現(xiàn),提供了標(biāo)準(zhǔn)的服務(wù)和一些有趣的和 OSGi 相關(guān)的服務(wù)實(shí)現(xiàn)。2 環(huán)境搭建既然是基于Equinox開發(fā),我們首先要下載Equinox。Equinox是Eclipse的工程,Eclipse 3.1之后的版本都是通過它來啟動(dòng)的,如果使用的是Eclipse 3.1之后的版本,Eclipse本身就已經(jīng)包含了equinox。所以我們要用Eclipse 3.1之后的版本。下面我們來檢查環(huán)境,首先啟動(dòng)Eclips

5、e。2.1 第一步,打開Run Configurations對(duì)話框(見下圖2-1)2-12.2 第二步,創(chuàng)建OSGI Framework類型的新的運(yùn)行配置(見下圖2-2)2-22.3 第三步,顯示所有的Bundles(見圖2-3)同時(shí)給這個(gè)新建的環(huán)境命名(例如:com.ypl.jr.test.helloworld.bunld)2-32.4 第四步,取消對(duì)Bunkles的選擇(見下圖2-4)2.5 第五步,選擇org.eclipse.osgi這個(gè)Bundle(見下圖2-5)2-52.6 第六步,運(yùn)行點(diǎn)擊Run按鈕,如果Console中出現(xiàn)了“OSGi>”并且沒有錯(cuò)誤信息,說明環(huán)境已經(jīng)正常了

6、。我們可以O(shè)SGi>提示符后輸入ss,然后回車。環(huán)境已經(jīng)準(zhǔn)備好了。下面來開始我們的第一個(gè)OSGI的應(yīng)用。3 Hello World!編寫第一個(gè) OSGi 應(yīng)用程序今天我們的HelloWorld例子程序主要功能是在啟動(dòng)和停止一個(gè)Bundle的時(shí)候來做些事情(輸出信息)。下面我們就一步一步完成第一個(gè)Bundle。3.1 第一步,建立一個(gè) plug-in 工程,F(xiàn)ile > New > Project,選擇 Plug-in development > Plug-in Project(見下圖3-1)Ø 輸入工程相關(guān)的信息,這里和創(chuàng)建普通的java工程唯一的不同點(diǎn)就是要

7、選擇this plug-in is targeted to run with,在這里an OSGI framework 的standard選項(xiàng),也就是說建立一個(gè)標(biāo)準(zhǔn)的OSGI Bundle工程Ø 輸入Bundle的相關(guān)數(shù)據(jù)信息l Plug-in ID指的是Bundle的唯一標(biāo)識(shí),在實(shí)際的項(xiàng)目中可以采用類似java的包名組織策略來保證標(biāo)識(shí)的唯一性;l Plug-in Version指的是Bundle的版本;l Plug-in name 指的是Bundle的更具有意義的名稱;l Plug-in Provider指的是Bundle運(yùn)行需要的環(huán)境;l 剩下的最關(guān)鍵的就是Activator部分

8、了,這里填入自己的一個(gè)類名就可以了,在工程建立時(shí)Ecliple會(huì)自動(dòng)建立這個(gè)類。完成了Bundle工程的創(chuàng)建后,在Package視圖中就可以看到如圖1-10這樣的視圖,表明工程創(chuàng)建成功了。3.2 第二步,完成Activator的代碼。Ø 打開默認(rèn)的Activator.java,編輯 Activator.java,輸入 hello world 語句,代碼如下:package com.ypl.jrywb.osgi.test.helloworld;import org.osgi.framework.BundleActivator;import org.osgi.framework.Bund

9、leContext;public class Activator implements BundleActivator private static BundleContext context;static BundleContext getContext() return context;/* * (non-Javadoc) * see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */public void start(BundleContext context) throws Exce

10、ption Activator.context = context;System.out.println("hello world");/* * (non-Javadoc) * see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */public void stop(BundleContext context) throws Exception Activator.context = null;我們可以看到每個(gè) Activator 實(shí)際都是實(shí)現(xiàn)了 BundleActiva

11、tor 接口,此接口使Activator 能夠接受框架的調(diào)用。在框架啟動(dòng)后,啟動(dòng)每個(gè) bundle 的時(shí)候都會(huì)調(diào)用每bundle 的 Activator 。每個(gè)Activator中有兩個(gè)空的方法start和stop。其中,start方法是在Bundle被啟動(dòng)的時(shí)候調(diào)用的,stop是在Bundle被停止的時(shí)候調(diào)用的,下面我們?cè)谶@兩個(gè)方法中加入代碼。注意:bundle 的 Activator 必須含有無參數(shù)構(gòu)造函數(shù),這樣框架才能使用 Class.newInstance() 方式反射構(gòu)造 bundle 的 Activator 實(shí)例。這里我們?cè)?start 方法中填入了我們希望輸出的 hello wo

12、rld 字符串。那么,怎么才能啟動(dòng)這個(gè) bundle 呢?3.3 第三步,執(zhí)行選擇 Run >Run Configurations ,進(jìn)入運(yùn)行菜單,在 OSGi framework 中點(diǎn)擊選擇先前新建的 OSGi 運(yùn)行環(huán)境,start level 和依賴的插件,由于我們目前不需要其它的第三方插件,因此只需要勾上系統(tǒng)的org.eclipse.osgi 插件,如果不選擇此插件,hello world 將無法運(yùn)行。只有當(dāng)您點(diǎn)擊了 validate bundles 按鈕 ,并且提示無問題之后,才表明您的運(yùn)行環(huán)境基本 OK 了,然后點(diǎn)擊Run。如圖:運(yùn)行結(jié)果如下:4 OSGi 控制臺(tái)OSGi 控制

13、臺(tái)對(duì)于習(xí)慣開發(fā)普通 Java 應(yīng)用程序的開發(fā)人員來說,還是比較新鮮的。一般來說,通過 OSGi 控制臺(tái),您可以對(duì)系統(tǒng)中所有的 bundle 進(jìn)行生命周期的管理,另外也可以查看系統(tǒng)環(huán)境,啟動(dòng)、停止整個(gè)框架,設(shè)置啟動(dòng)級(jí)別等等操作。如圖 10,鍵入 SS 就可以查看所有 bundle 的狀態(tài):接著,我們輸入stop com.ypl.jr.test.helloworld.bunld,并且再用命令ss查看Bundle的狀態(tài),會(huì)得到如下所示的反饋。下面列出了主要的控制臺(tái)命令:表 1. Equinox OSGi 主要的控制臺(tái)命令表類別 命令 含義 控制框架launch 啟動(dòng)框架shutdown 停止框架cl

14、ose 關(guān)閉、退出框架exit 立即退出,相當(dāng)于 System.exitinit 卸載所有 bundle(前提是已經(jīng) shutdown)setprop 設(shè)置屬性,在運(yùn)行時(shí)進(jìn)行控制 bundleInstall 安裝uninstall 卸載Start 啟動(dòng)Stop 停止Refresh 刷新Update 更新展示狀態(tài)Status 展示安裝的 bundle 和注冊(cè)的服務(wù)Ss 展示所有 bundle 的簡(jiǎn)單狀態(tài)Services 展示注冊(cè)服務(wù)的詳細(xì)信息Packages 展示導(dǎo)入、導(dǎo)出包的狀態(tài)Bundles 展示所有已經(jīng)安裝的 bundles 的狀態(tài)Headers 展示 bundles 的頭信息,即 MAN

15、IFEST.MF 中的內(nèi)容Log 展示 LOG 入口信息其它Exec 在另外一個(gè)進(jìn)程中執(zhí)行一個(gè)命令(阻塞狀態(tài))Fork 和 EXEC 不同的是不會(huì)引起阻塞Gc 促使垃圾回收Getprop 得到屬性,或者某個(gè)屬性控制啟動(dòng)級(jí)別Sl 得到某個(gè) bundle 或者整個(gè)框架的 start level 信息Setfwsl 設(shè)置框架的 start levelSetbsl 設(shè)置 bundle 的 start levelsetibsl 設(shè)置初始化 bundle 的 start level·5 發(fā)布和使用5.1 知識(shí)點(diǎn)介紹好的,剛才我們已經(jīng)從頭到尾開發(fā)了一個(gè)基于 Equinox 框架的 Hello wo

16、rld 應(yīng)用程序。我們發(fā)現(xiàn)似乎并不是很困難,很多工作 Eclipse 已經(jīng)幫我們做好了,例如 Activator 代碼框架和 MANIFEST.MF 文件,我們也學(xué)會(huì)了如何控制 OSGi 的控制臺(tái)和編寫 MANIFEST.MF 文件,但是,您真的明白它們是如何運(yùn)行的么?下面我們將重點(diǎn)介紹一些 OSGi 運(yùn)行必備的基礎(chǔ)知識(shí)。Ø 什么是 bundle?我們已經(jīng)看到,編寫一個(gè)很普通的 Hello world 應(yīng)用,必須首先創(chuàng)建一個(gè) plug-in 工程,然后編輯其 Activator 類的 start 方法,實(shí)際我們這樣做的本質(zhì)是為 OSGi 運(yùn)行環(huán)境添加了一個(gè) bundle,那么一個(gè) b

17、undle 必須的構(gòu)成元素是哪些呢?MANIFEST.MF:描述了 bundle 的所有特征,包括名字、輸出的類或者包,導(dǎo)入的類或者包,版本號(hào)等等,具體可以參考 表 2. MANIFEST.MF 文件屬性。 代碼:包括 Activator 類和其它一些接口以及實(shí)現(xiàn),這個(gè)和普通的 Java 應(yīng)用程序沒有什么特殊的區(qū)別。資源:當(dāng)然,一個(gè)應(yīng)用程序不可能沒有資源文件,比如圖片、properties 文件、XML 文件等等,這些資源可以隨 bundle 一起存在,也可以以 fragment bundle 的方式加入。啟動(dòng)級(jí)別的定義:可以在啟動(dòng)前使用命令行參數(shù)指定,也可以在運(yùn)行中指定,具體的 start

18、level 的解釋,請(qǐng)參考 后面的說明。 Ø 框架做了些什么?好了,我們已經(jīng)明白 bundle 是什么了,也知道如何開發(fā)一個(gè)基本的 bundle 了,那么我們還必須要明白,我的 bundle 放在 Equinox 框架中,它對(duì)我們的 bundle 做了些什么?實(shí)際上,目標(biāo)平臺(tái)已經(jīng)為我們準(zhǔn)備了 N 個(gè) bundle,它們提供各種各樣的服務(wù),OSGi 中,這些 bundle 的名字叫 system bundle,就好比精裝修的房子,您只需要拎包入住,不再需要自己鋪地板,裝吊頂了。我們的 bundle 進(jìn)入 Equinox 環(huán)境后,OSGi 框架對(duì)其做的事情如下:讀入 bundle 的 h

19、eaders 信息,即 MANIFEST.MF 文件;裝載相關(guān)的類和資源;解析依賴的包;調(diào)用其 Activator 的 start 方法,啟動(dòng)它;為其提供框架事件、服務(wù)事件等服務(wù);調(diào)用其 Activator 的 stop 方法,停止它;Ø Bundle 的狀態(tài)變更OK, 現(xiàn)在我們大概明白了一個(gè) bundle 的定義和其在 OSGi 框架中的生命周期,前面我們看到控制臺(tái)可以通過 ss 命令查看所有裝載的 bundle 的狀態(tài),那么 bundle 到底具有哪些狀態(tài),這些狀態(tài)之間是如何變換呢?我們知道了這些狀態(tài)信息,對(duì)我們有何益處?首先,了解一下一個(gè) bundle 到底有哪些狀態(tài):

20、6; Bundle 狀態(tài)狀態(tài)名字 含義 INSTALLED 就是字面意思,表示這個(gè) bundle 已經(jīng)被成功的安裝了RESOLVED 很常見的一個(gè)狀態(tài),表示這個(gè) bundle 已經(jīng)成功的被解析(即所有依賴的類、資源都找到了),通常出現(xiàn)在啟動(dòng)前或者停止后STARTING 字面意思,正在啟動(dòng),但是還沒有返回,所以您的 Activator 不要搞的太復(fù)雜ACTIVE 活動(dòng)的,這是我們最希望看到的狀態(tài),通常表示這個(gè) bundle 已經(jīng)啟動(dòng)成功,但是不意味著您的 bundle 提供的服務(wù)也是 OK 的STOPPING 字面意思,正在停止,還沒有返回UNINSTALLED 卸載了,狀態(tài)不能再發(fā)生變更了&#

21、216; Bundle 導(dǎo)入導(dǎo)出 packageOK,到現(xiàn)在為止,似乎一切都是新鮮的,但是您似乎在考慮,OSGi 到底有什么優(yōu)勢(shì),下面介紹一下其中的一個(gè)特點(diǎn),幾乎所有的面向組件的框架都需要這一點(diǎn)來實(shí)現(xiàn)其目的: 面向服務(wù)、封裝實(shí)現(xiàn) 。這一點(diǎn)在普通的 Java 應(yīng)用是很難做到的,所有的類都暴露在 classpath 中,人們可以隨意的查看您的實(shí)現(xiàn),甚至變更您的實(shí)現(xiàn)。這一點(diǎn),對(duì)于希望發(fā)布組件的公司來說是致命的。OSGi 很好的解決了這個(gè)問題,就像上面的圖顯示的,每個(gè) bundle 都可以有自己公共的部分和隱藏的部分,每個(gè) bundle 也只能看見自己的公共部分、隱藏部分和其它 bundle 的公共部

22、分。bundle 的 MANIFEST.MF 文件提供了 EXPORT/IMPORT package 的關(guān)鍵字,這樣您可以僅僅 export 出您希望別人看到的包,而隱藏實(shí)現(xiàn)的包。并且您可以為它們編上版本號(hào),這樣可以同時(shí)發(fā)布不同版本的包。Ø Bundle class path這一點(diǎn)比較難理解,一般情況下您不需要關(guān)心這個(gè)事情,除非事情出現(xiàn)了問題,您發(fā)現(xiàn)明明這個(gè)類就在這里,怎么就是報(bào)告 ClassNotFoundException/NoClassDefExcpetion 呢?在您垂頭喪氣、準(zhǔn)備砸掉電腦顯示器之前,請(qǐng)看一下 bundle 中的類是如何查找的:首先,它會(huì)找 JRE,這個(gè)很明顯

23、,這個(gè)實(shí)際是通過系統(tǒng)環(huán)境的 JAVA_HOME 中找到的,路徑一般是 JAVA_HOME/lib/rt.jar、tools.jar 和 ext 目錄,endorsed 目錄。其次,它會(huì)找 system bundle 導(dǎo)出的包。然后,它會(huì)找您的 import 的包,這個(gè)實(shí)際包含兩種:一種是直接通過 require-bundle 的方式全部導(dǎo)入的,還有一種就是前面講的通過 import package 方式導(dǎo)入的包。查找它的 fragment bundle,如果有的話。如果還沒有找到,則會(huì)找自己的 classpath 路徑(每個(gè) bundle 都有自己的類路徑)。最后它會(huì)嘗試根據(jù) DynamicI

24、mport-Package 屬性查找的引用。Ø 啟動(dòng)級(jí)別 Start level在 Equinox 環(huán)境中,我們?cè)谂渲?hello world 應(yīng)用的時(shí)候,看到我們將 framework start level 保持為 4,將 Hello world bundle 的 start level 設(shè)置為 5 。 start level 越大,表示啟動(dòng)的順序越靠后。在實(shí)際的應(yīng)用環(huán)境中,我們的 bundle 互相有一定的依賴關(guān)系,所以在啟動(dòng)的順序上要有所區(qū)別,好比蓋樓,要從打地基開始。實(shí)際上,OSGi 框架最初的 start level 是 0,啟動(dòng)順序如下:將啟動(dòng)級(jí)別加一,如果發(fā)現(xiàn)有匹配的

25、 bundle(即 bundle 的啟動(dòng)級(jí)別和目前的啟動(dòng)級(jí)別相等),則啟動(dòng)這個(gè) bundle;繼續(xù)第一步,直到發(fā)現(xiàn)已經(jīng)啟動(dòng)了所有的 bundle,且活動(dòng)啟動(dòng)級(jí)別和最后的啟動(dòng)的 bundle 啟動(dòng)級(jí)別相同。停止順序,也是首先將系統(tǒng)的 start level 設(shè)置為 0:由于系統(tǒng)當(dāng)前活動(dòng)啟動(dòng)級(jí)別大于請(qǐng)求的 start level,所以系統(tǒng)首先停止等于當(dāng)前活動(dòng)啟動(dòng)級(jí)別的 bundle;將活動(dòng)啟動(dòng)級(jí)別減一,繼續(xù)第一步,直到發(fā)現(xiàn)活動(dòng)啟動(dòng)級(jí)別和請(qǐng)求級(jí)別相等,都是 0。5.2 開發(fā)一個(gè)真實(shí)的 OSGi 應(yīng)用程序我們不能只停留在 hello world 的層面,雖然那曾經(jīng)對(duì)我們很重要 ,但是現(xiàn)實(shí)需要我們能夠使

26、用 OSGi 寫出激動(dòng)人心的應(yīng)用程序,它能夠被客戶接受,被架構(gòu)師認(rèn)可,被程序員肯定。好的,那我們開始吧。下面將會(huì)著重介紹一些現(xiàn)實(shí)的應(yīng)用程序可能需要的一些 OSGi 應(yīng)用場(chǎng)景。5.2.1 創(chuàng)建一個(gè)實(shí)現(xiàn)由于 OSGi 框架能夠方便的隱藏實(shí)現(xiàn)類,所以對(duì)外提供接口是很自然的事情,OSGi 框架提供了服務(wù)的注冊(cè)和查詢功能。好的,那么我們實(shí)際操作一下,就在 Hello world 工程的基礎(chǔ)上進(jìn)行。我們需要進(jìn)行下列的步驟:Ø 定義一個(gè)服務(wù)接口,并且 export 出去供其它 bundle 使用;Ø 定義一個(gè)缺省的服務(wù)實(shí)現(xiàn),并且隱藏它的實(shí)現(xiàn);Ø Bundle 啟動(dòng)后,需要將服務(wù)

27、注冊(cè)到 Equinox 框架;Ø 從框架查詢這個(gè)服務(wù),并且測(cè)試可用性。好的,為了達(dá)到上述要求,我們實(shí)際操作如下:Ø 定義一個(gè)新的包c(diǎn)om.ypl.jrywb.osgi.helloworkd.service用來存放接口。單獨(dú)一個(gè) package 的好處是,您可以僅僅 export 這個(gè) package 給其它 bundle 而隱藏所有的實(shí)現(xiàn);Ø 在上述的包中新建接口 IHello,提供一個(gè)簡(jiǎn)單的字符串服務(wù),代碼如下:package com.ypl.jrywb.osgi.test.helloworld.service;public interface IHello /

28、* 得到IHello接口的信息,僅僅只是輸出一些字符串* return String*/public String sayHello();Ø 再新建一個(gè)新的包 com.ypl.jrywb.osgi.test.helloworld.impl,用來存放實(shí)現(xiàn)類。package com.ypl.jrywb.osgi.test.helloworld.impl;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceReference;import org.osgi.service.event.EventA

29、dmin;import com.ypl.jrywb.osgi.test.helloworld.service.IHello;public class DefaultHelloServiceImpl implements IHello private BundleContext bundleContext;public DefaultHelloServiceImpl(BundleContext bundleContext)this.bundleContext = bundleContext;Overridepublic String sayHello() ServiceReference ref

30、 = bundleContext.getServiceReference(EventAdmin.class.getName();if(ref != null)EventAdmin eventAdmin = (EventAdmin) bundleContext.getService(ref);if(eventAdmin != null)System.out.println("post Event start.");System.out.println("可以在這里觸發(fā)事件");System.out.println("post Event retu

31、rned.");return "hello,osgi,service!"Ø 在上述包中新建 DefaultHelloServiceImpl 類,實(shí)現(xiàn)上述接口;由于下列代碼中要用到事件類,所以需要在META-IN>MANIFEST.MF文件中的Dependencies中的Imported Packages中添加org.osgi.service.event包:5.2.2 注冊(cè)服務(wù)OSGi 框架提供了兩種注冊(cè)方式,都是通過 BundleContext 類實(shí)現(xiàn)的:Ø registerService(String,Object,Dictionary

32、) 注冊(cè)服務(wù)對(duì)象 object 到接口名 String 下,可以攜帶一個(gè)屬性字典 Dictionary;Ø registerService(String,Object,Dictionary) 注冊(cè)服務(wù)對(duì)象 object 到接口名數(shù)組 String 下,可以攜帶一個(gè)屬性字典 Dictionary,即一個(gè)服務(wù)對(duì)象可以按照多個(gè)接口名字注冊(cè),因?yàn)轭惪梢詫?shí)現(xiàn)多個(gè)接口;我們使用第一種注冊(cè)方式,修改 Activator 類的 start 方法,加入注冊(cè)代碼:public void start(BundleContext bundleContext) throws Exception Activat

33、or.context = bundleContext;System.out.println("hello world");context.registerService(IHello.class.getName(),new DefaultHelloServiceImpl(bundleContext),null);5.2.3 發(fā)布服務(wù)為了讓我們的服務(wù)能夠被其它 bundle 使用,必須在 MANIFEST.MF 中對(duì)其進(jìn)行導(dǎo)出聲明,雙擊 MANIFEST.MF,找到 runtime > exported packages > 點(diǎn)擊 add,如圖,選擇 servic

34、e 包即可:5.2.4 服務(wù)使用另外新建一個(gè)類似于 hello world 的 bundle 叫:com.ypl.jrywb.osgi.test.helloworld2,用于測(cè)試com.ypl.jrywb.osgi.test.helloworld提供的服務(wù)的可用性;添加 import package:在第二個(gè) bundlecom.ypl.jrywb.osgi.test.helloworld2 的 MANIFEST.MF 文件中,找到 dependencies > Imported packages > Add ,選擇我們剛才 export 出去的 com.ypl.jrywb.osg

35、i.test.helloworld.service 包,將其包含在內(nèi):查詢服務(wù):同樣,OSGi 框架提供了兩種查詢服務(wù)的引用 ServiceReference 的方法: Ø getServiceReference(String):根據(jù)接口的名字得到服務(wù)的引用;Ø getServiceReferences(String,String):根據(jù)接口名和另外一個(gè)過濾器名字對(duì)應(yīng)的過濾器得到服務(wù)的引用;這里我們使用第一種查詢的方法,在 com.ypl.jrywb.osgi.test.helloworld2 bundle 的 Activator 的 start 方法加入查詢和測(cè)試語句:p

36、ackage com.ypl.jrywb.osgi.test.helloworld2;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import com.ypl.jrywb.osgi.test.helloworld.service.IHello;public class Activator implements BundleActivator private static BundleContext context;static BundleContext getContext

37、() return context;/* * (non-Javadoc) * see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */public void start(BundleContext bundleContext) throws Exception Activator.context = bundleContext;System.out.println("hello world2");IHello helloService = (IHello) contex

38、t.getService(context.getServiceReference(IHello.class.getName();System.out.println(helloService.sayHello(); /* * (non-Javadoc) * see */public void stop(BundleContext context) throws Exception Activator.context = null;5.2.5 修改運(yùn)行環(huán)境因?yàn)槲覀冊(cè)黾恿艘粋€(gè) bundle,所以說也需要在運(yùn)行配置中加入對(duì)新的 bundle 的配置信息,如下圖所示:5.2.6 運(yùn)行結(jié)果如下6 使用事

39、件管理服務(wù) EventAdmin前面講過,OSGi 規(guī)范定義了很多可用的 bundle,您盡管使用它們完成您的工作,而不必另外再發(fā)明輪子,OSGi 框架定義的事件管理服務(wù),類似于 JMS,但是使用上比 JMS 簡(jiǎn)單。OSGi 整個(gè)框架都離不開這個(gè)服務(wù) ,因?yàn)榭蚣芾锩嫒家揽渴录C(jī)制進(jìn)行通信,例如 bundle 的啟動(dòng)、停止,框架的啟動(dòng)、停止,服務(wù)的注冊(cè)、注銷等等等等都是會(huì)發(fā)布事件給監(jiān)聽者,同時(shí)也在監(jiān)聽其它模塊發(fā)來的自己關(guān)心的事件。 OSGi 框架的事件機(jī)制主要核心思想是:Ø 用戶(程序員)可以自己按照接口定義自己的事件類型Ø 用戶可以監(jiān)聽自己關(guān)心的事件或者所有事件Ø

40、; 用戶可以將事件同步的或者異步的提交給框架,由框架負(fù)責(zé)同步的或者異步的分發(fā)給監(jiān)聽者說明:框架提供的事件服務(wù)、事件提供者、事件監(jiān)聽者之間的關(guān)系如下:事件提供者 Publisher 可以獲取 EventAdmin 服務(wù),通過 sendEvent 同步(postEvent 異步)方式提交事件,EventAdmin 服務(wù)負(fù)責(zé)分發(fā)給相關(guān)的監(jiān)聽者 EventHandler,調(diào)用它們的 handleEvent 方法。這里要介紹一個(gè)新的概念 Topics,其實(shí)在 JMS 里面也有用,也就是說一個(gè)事件一般都有一個(gè)主題,這樣我們的事件接收者才能按照一定的主題進(jìn)行過濾處理,例如只處理自己關(guān)心的主題的事件,一般情況

41、下主題是用類似于 Java Package 的命名方式命名的。同步提交(sendEvent)和異步提交(postEvent) 事件的區(qū)別是,同步事件提交后,等框架分發(fā)事件給所有事件接收者之后才返回給事件提交者,而異步事件則一經(jīng)提交就返回了,分發(fā)在另外的線程進(jìn)行處理。下面的程序演示了事件的定義、事件的發(fā)布、事件處理,同時(shí)還演示了同步和異步處理的效果,以及運(yùn)行環(huán)境的配置。(約定 com.ypl.jrywb.osgi.test.helloworld 為 bundle1,com.ypl.jrywb.osgi.test.helloworld2 為 bundle2)6.1 定義事件類Ø 在 bu

42、ndle1 中的 MANIFEST.MF 的 dependency 頁(yè)面中定義引入新的包:org.osgi.service.event。此包為事件包,調(diào)用事件類Ø 在 bundle1 中的 osgi.test.helloworld.event 包中定義新的類 MyEvent,如下(注意其中的 topic 定義的命名方式): package com.ypl.jrywb.osgi.test.helloworld.event;import java.util.Dictionary;import org.osgi.service.event.Event;public class MyEven

43、t extends Event private static final long serialVersionUID = 1L;public static final String MY_TOPIC = "osig/test/helloworld/event/MyEvent"public MyEvent(String topic, Dictionary<String,?> properties) super(MY_TOPIC, properties);public MyEvent() this(MY_TOPIC, null); public String toS

44、tring() return "MyEvent"在 bundle1 的 DefaultHelloServiceImpl類的 sayHello 方法中,加入提交事件的部分,這樣 bundle2 在調(diào)用這個(gè)服務(wù)的時(shí)候,將觸發(fā)一個(gè)事件,由于采用了 Post 方式,應(yīng)該是立刻返回的,所以在 postEvent 前后打印了語句進(jìn)行驗(yàn)證。package com.ypl.jrywb.osgi.test.helloworld.impl;import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceRefer

45、ence;import org.osgi.service.event.EventAdmin;import com.ypl.jrywb.osgi.test.helloworld.event.MyEvent;import com.ypl.jrywb.osgi.test.helloworld.service.IHello;public class DefaultHelloServiceImpl implements IHello private BundleContext bundleContext;public DefaultHelloServiceImpl(BundleContext bundl

46、eContext)this.bundleContext = bundleContext;Overridepublic String sayHello() ServiceReference ref = bundleContext.getServiceReference(EventAdmin.class.getName();if(ref != null)EventAdmin eventAdmin = (EventAdmin) bundleContext.getService(ref);if(eventAdmin != null)System.out.println("post Event

47、 start.");/System.out.println("可以在這里觸發(fā)事件");eventAdmin.sendEvent(new MyEvent();System.out.println("post Event returned.");return "hello,osgi,service!"6.2 定義監(jiān)聽者在 bundle2 中,也引入 osgi 的事件包osgi.test.helloworld.event,然后定義一個(gè)新的類:MyEventHandler 類,用來處理事件,這里故意加入了一個(gè)延遲,是為了測(cè)試異步事件

48、的調(diào)用,實(shí)現(xiàn)如下:package com.ypl.jrywb.osgi.test.helloworld2.impl;import org.osgi.service.event.Event;import org.osgi.service.event.EventHandler;public class MyEventHandler implements EventHandler Overridepublic void handleEvent(Event event) System.out.println("handler event start - " + event);try

49、 Thread.currentThread().sleep(10*1000); catch (InterruptedException e) e.printStackTrace();/ TODO: handle exceptionSystem.out.println("handler event ok - " + event);6.3 注冊(cè)監(jiān)聽器有了事件處理器,還需要注冊(cè)到監(jiān)聽器中,這里在 bundle2 的 Activator 類中加入此監(jiān)聽器,也就是調(diào)用 context.registerService 方法注冊(cè)這個(gè)監(jiān)聽服務(wù),和普通服務(wù)的區(qū)別是要帶一個(gè)監(jiān)聽事件類型的 to

50、pic,首先還要在bundle2 中的MANIFEST.MF,找到 Dependencies中的Imported Packages中添加com.ypl.jrywb.osgi.test.helloworld.event,包:點(diǎn)擊 add加入event事件包,將事件發(fā)布出去,若找不到,可在MANIFEST.MF中手動(dòng)添加,這里列出 Activator 類的 start 方法:public void start(BundleContext bundleContext) throws Exception Activator.context = bundleContext;System.out.prin

51、tln("hello world2");String topics = new StringMyEvent.MY_TOPIC;Hashtable<String, String> ht = new Hashtable<String, String>();ht.put(EventConstants.EVENT_TOPIC, topics);MyEventHandler eventHandler = new MyEventHandler();context.registerService(EventHandler.class.getName(), even

52、tHandler, ht);System.out.println("event Handler registered .");IHello helloService = (IHello) context.getService(context.getServiceReference(IHello.class.getName();System.out.println(helloService.sayHello();6.4 修改運(yùn)行環(huán)境執(zhí)行為了使用框架的事件服務(wù),需要修改運(yùn)行環(huán)境,加入兩個(gè)系統(tǒng) bundle,分別是: a. org.eclipse.osgi.services b.

53、 org.eclipse.equinox.event 如果org.eclipse.equinox.event 沒有找到,這可能需要jar包放在Eclipse中的plugins文件夾下,重啟Eclipse,在MANIFEST.MF中的Required Plug-in中添加。運(yùn)行結(jié)果:可以看到,post 事件后,不等事件真的被處理完成,就返回了,事件處理在另外的線程執(zhí)行,最后才打印處理完成的語句。然后 ss 看一下,目前我們已經(jīng)有五個(gè) bundle 在運(yùn)行了:OK,修改代碼以測(cè)試同步調(diào)用的情況,我們只需要把提交事件的代碼由 postEvent 修改為 sendEvent 即可。其它不變,測(cè)試結(jié)果如

54、下:6.5 使用 Http 服務(wù) HttpServiceOSGi 的 HTTP 服務(wù)為我們提供了展示 OSGi 的另外一個(gè)途徑,即我們可以專門提供一個(gè) bundle 用來作為我們應(yīng)用的 UI,當(dāng)然這個(gè)還比較簡(jiǎn)單,只能提供基本的 HTML 服務(wù)和基本的 Servlet 服務(wù)。如果想提供復(fù)雜的 Jsp/Struts/WebWorks 等等,或者想用現(xiàn)有的 Web 中間件服務(wù)器例如 Tomcat/Resin/WebSphere Application Server 等,都需要另外的途徑來實(shí)現(xiàn),目前我提供一些基本的使用 HTTP 服務(wù)的方式。要使用 HTTP 服務(wù),必然有三個(gè)步驟:Ø 獲取

55、HttpService,可以像 上述方式 那樣通過 context 的 getService 方法獲得引用;Ø 使用 HttpService 的引用注冊(cè)資源或者注冊(cè) Servlet: a) registerResources:注冊(cè)資源,提供本地路徑、虛擬訪問路徑和相關(guān)屬性即可完成注冊(cè),客戶可以通過虛擬訪問路徑 + 資源名稱訪問到資源b) registerServlet:注冊(cè) Servlet,提供標(biāo)準(zhǔn) Servlet 實(shí)例、虛擬訪問路徑、相關(guān)屬性以及 HttpContext(可以為 null)后即可完成注冊(cè),客戶可以直接通過虛擬訪問路徑獲取該 Servlet 的訪問Ø 修改運(yùn)

56、行環(huán)境,加入支持 http 服務(wù)的 bundle那么,接下來我們實(shí)際操作一下:首先,在 bundle1 的 src 中建立一個(gè)新的 package,名字叫 pages,用來存放一些 HTML 的資源文件,為了提供一個(gè)基本的 HTTP 服務(wù),我們需要提供一個(gè) index.html,內(nèi)容如下: 第二步,注冊(cè)資源服務(wù),首先我們要為 bundle1 加入 HTTP 服務(wù)的 package 引用,即修改 MANIFEST.MF 文件的 dependencies,加入包:org.osgi.service.http;version="1.2.1",然后在 Activator 類的 start 方法中加入 HTTP 資源的注冊(cè): public void start(BundleContext bundleContext) throws Exception Activator.context = bundleContext;System.out.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論