laineysgl |
|
|||
日歷
統(tǒng)計(jì)
導(dǎo)航留言簿文章檔案搜索最新評論
|
OSGI(Open Services Gateway Initiative),或者通俗點(diǎn)說JAVA動態(tài)模塊系統(tǒng),定義了一套模塊應(yīng)用開發(fā)的框架。OSGI容器實(shí)現(xiàn)方案如Knopflerfish, Equinox, and Apache Felix允許你把你的應(yīng)用分成多個(gè)功能模塊,這樣通過依賴管理這些功能會更加方便。 和Servlet和EJB規(guī)范類似,OSGI規(guī)范包含兩大塊:一個(gè)OSGI容器需要實(shí)現(xiàn)的服務(wù)集合;一種OSGI容器和應(yīng)用之間通信的機(jī)制。開發(fā)OSGI平臺意味著你需要使用OSGI API編寫你的應(yīng)用,然后將其部署到OSGI容器中。從開發(fā)者的視角來看,OSGI提供以下優(yōu)勢:
OK,你已經(jīng)有個(gè)Servlet容器來做web 應(yīng)用,有了EJB容器來做事務(wù)處理,你可能在想為什么你還需要一個(gè)新的容器?簡單點(diǎn)說,OSGI容器被設(shè)計(jì)專門用來開發(fā)可分解為功能模塊的復(fù)雜的Java應(yīng)用。
企業(yè)應(yīng)用領(lǐng)域的OSGI
OSGI規(guī)范最初是由OSGI聯(lián)盟在1999年3月發(fā)起。它的主要目的是成為向網(wǎng)絡(luò)設(shè)備傳輸服務(wù)管理的開放規(guī)范。核心思想是一旦你向網(wǎng)絡(luò)設(shè)備中添加了一個(gè)OSGI服務(wù)平臺,你可以在網(wǎng)絡(luò)中的任意位置管理該設(shè)備上的服務(wù)組件。這些服務(wù)組件可以任意安裝,更新或移除而不會對設(shè)備產(chǎn)生影響。 多年來,OSGI技術(shù)只出現(xiàn)在嵌入式系統(tǒng)和網(wǎng)絡(luò)設(shè)備市場。現(xiàn)在,Eclipse使OSGI在企業(yè)開發(fā)領(lǐng)域煥發(fā)出新的光彩。
OSGI受到越來越廣泛的支持
2003年,Eclipse開發(fā)團(tuán)隊(duì)開始尋找一種使eclipse成為一種功能更動態(tài)、工具更模塊化的富客戶端平臺。最終,他們的目光鎖定在OSGI框架上。Eclipse3.0,2004年6月發(fā)布,是基于OSGI技術(shù)搭建的首個(gè)Eclipse版本。
幾乎所有企業(yè)應(yīng)用服務(wù)提供商支持或計(jì)劃支持OSGI。Spring框架同樣支持OSGI,通過Spring DM(Spring Dynamic Modules for OSGI Service Platforms)項(xiàng)目,可以讓我們在Spring上更方便的應(yīng)用OSGI。
開源OSGI容器
從企業(yè)應(yīng)用開發(fā)者的角度看,OSGI容器侵入性非常小,你可以方便地將其嵌入一個(gè)企業(yè)應(yīng)用。舉個(gè)例子來說,假設(shè)你在開發(fā)一個(gè)復(fù)雜的web應(yīng)用。你希望將這個(gè)應(yīng)用分解成多個(gè)功能模塊。一個(gè)View層模塊,一個(gè)Model層模塊,一個(gè)DAO模塊。使用嵌入式OSGI容器來跨依賴地管理這些模塊可以讓你隨時(shí)更新你的DAO模塊卻不需要重啟你的服務(wù)器。 只要你的應(yīng)用完全符合OSGI規(guī)范,它就可以在所有符合OSGI規(guī)范的容器內(nèi)運(yùn)行。現(xiàn)在,有三種流行的開源OSGI容器:
在這篇文章里我們使用Equinox作為我們的OSGI容器。
嘗試開發(fā)一個(gè)Hello World bundle
在OSGI的領(lǐng)域,發(fā)布的軟件是以bundle的形式出現(xiàn)。bundle由java class類和資源文件組成,向設(shè)備所有者提供功能,同時(shí)可以為其他的bundles提供服務(wù)。Eclipse對開發(fā)bundles提供了強(qiáng)大的支持。Eclipse不僅僅提供創(chuàng)建bundles的功能,它還集成了Equinox這個(gè)OSGI容器,你可以在其上開發(fā)和調(diào)試OSGI組件。其實(shí)所有的Eclipse插件都是使用Eclipse規(guī)范代碼寫的OSGI bundle。接下來,你將可以學(xué)到如何使用Eclipse IDE開發(fā)一個(gè)Hello world osgi bundle。
開始開發(fā)bundle
我們一步步的開始:
Eclipse會飛快的為你創(chuàng)建Hello world bundle的模版代碼。主要包含兩個(gè)文件:Activator.java和MANIFEST.MF。
Activator.java的代碼如下所示:
如果你的bundle在啟動和關(guān)閉的時(shí)候需要被通知,你可以考慮實(shí)現(xiàn)BundleActivator接口。以下是定義Activator的一些注意點(diǎn):
MANIFEST.MF
這個(gè)文件是你的bundle的部署描述文件。格式和Jar里的MANIFEST.MF是一樣的。包含的不少名值對,就像如下:
分別來看下:
Bundle-ManifestVersion 數(shù)值為2意味著本bundle支持OSGI規(guī)范第四版;如果是1那就是支持OSGI規(guī)范第三版。 Bundle-Name 給bundle定義一個(gè)短名,方便人員閱讀 Bundle-SymbolicName 給bundle定義一個(gè)唯一的非局部名。方便分辨。 Bundle-Activator 聲明在start和stop事件發(fā)生時(shí)會被通知的監(jiān)聽類的名字。 Import-Package 定義bundle的導(dǎo)入包。
Hello World bundle完成了,接下來我們運(yùn)行一下。
執(zhí)行bundle
OSGI控制臺
OSGI控制臺是一個(gè)OSGI容器的命令行界面。你可以利用它做些諸如啟動,關(guān)閉,安裝bundles,更新和刪除bundles等操作。現(xiàn)在,點(diǎn)擊OSGI控制臺所在的位置,回車,你就會發(fā)現(xiàn)可以輸入命令了。這時(shí)的OSGI控制臺應(yīng)該如下圖: 下面列出一些常用的OSGI命令,你可以試著和OSGI容器交互。 ss 顯示已安裝的bundles的狀態(tài)信息,信息包括bundle ID,短名,狀態(tài)等等。 start 啟動一個(gè)bundle stop 關(guān)閉一個(gè)bundle update 載入一個(gè)新的JAR文件更新一個(gè)bundle install 安裝一個(gè)新的bundle到容器中 uninstall 卸載一個(gè)已在容器中的bundle
依賴管理
OSGI規(guī)范允許你把你的應(yīng)用分解成多個(gè)模塊然后管理各個(gè)模塊間的依賴關(guān)系。 這需要通過bundle scope來完成。默認(rèn)情況下,一個(gè)bundle內(nèi)的class對其他bundle來說是不可見的。那么,如果要讓一個(gè)bundle訪問另一個(gè)bundle里的class要怎么做?解決的方案就是從源bundle導(dǎo)出包,然后在目標(biāo)bundle里導(dǎo)入。 接下來我們對此做一個(gè)例子。
首先,我們需要先創(chuàng)建一個(gè)com.howard.sample.HelloService bundle,我們將通過它導(dǎo)出一個(gè)包。 然后,我們在com.howard.sample.HelloWorld 這個(gè)bundle里導(dǎo)入包。
導(dǎo)出包
1、創(chuàng)建名為com.howard.sample.HelloService的bundle,創(chuàng)建步驟和前面一樣。 2、在這個(gè)bundle內(nèi),添加一個(gè)com.howard.sample.service.HelloService.java 接口,代碼如下:
3、創(chuàng)建一個(gè)com.howard.sample.service.impl.HelloServiceImpl.java類實(shí)現(xiàn)剛才的接口:
4、打開MANIFEST.MF,選擇Runtime標(biāo)簽項(xiàng),在Exported Packages選項(xiàng)欄,點(diǎn)擊Add并且選擇com.howard.sample.service這個(gè)包。然后MANIFEST.MF的代碼應(yīng)該如下:
你可以看到,MANIFEST.MF文件和剛才的HelloWorld的那份很類似。唯一的區(qū)別就是這個(gè)多了Export-Package這個(gè)標(biāo)記,對應(yīng)的值就是我們剛才選擇的com.howard.sample.service。 Export-Package標(biāo)記告訴OSGI容器在com.howard.sample.service包內(nèi)的classes可以被外部訪問。 注意,我們僅僅暴露了HelloService接口,而不是直接暴露HelloServiceImpl實(shí)現(xiàn)。
導(dǎo)入包
接下來我們要更新原來的HelloWorld bundle以導(dǎo)入com.howard.sample.service包。步驟如下:
1、進(jìn)入HelloWorld bundle,打開MANIFEST.MF,進(jìn)入Dependencies標(biāo)簽頁,在Imported Packages里添加com.howard.sample.service。MANIFEST.MF文件應(yīng)該如下所示:
沒錯(cuò),Import-package標(biāo)記的值也就是導(dǎo)入的包名之間是用逗號隔開的。在這里導(dǎo)入了兩個(gè)包om.howard.sample.service和org.osgi.framework。后者是使用Activator類時(shí)必須導(dǎo)入的包。
2、接下來,打開HelloWorld項(xiàng)目下的Activator.java文件,這時(shí)候你會發(fā)現(xiàn)可以使用HelloService這個(gè)接口了。但還是不能使用HelloServiceImpl實(shí)現(xiàn)類。Eclipse會告訴你:Access restriction(立入禁止)。
Class級別可見域
為什么OSGI容器可以做到讓jar包中的一些classes可見而另一些又不可見呢。 答案其實(shí)就是OSGI容器自定義了java class loader來有選擇的加載類。OSGI容器為每一個(gè)bundle都創(chuàng)建了不同的class loader。因此,bundle可以訪問的classes包括
bundle級別的可見域允許你可以隨時(shí)放心的更改HelloServiceImpl實(shí)現(xiàn)類而不需要去擔(dān)心依賴關(guān)系會被破壞。
OSGI服務(wù)
OSGI框架是實(shí)現(xiàn)SOA的絕佳土壤。通過它可以實(shí)現(xiàn)bundles暴露服務(wù)接口給其他bundles消費(fèi)而不需要讓細(xì)節(jié)暴露。消費(fèi)bundles甚至可以完全不知道提供服務(wù)的bundles。憑著可以良好的隱藏具體實(shí)現(xiàn)的能力,OSGI當(dāng)之無愧是SOA的一種較完美的實(shí)現(xiàn)方案。
OSGI中,提供服務(wù)的bundle在OSGI容器上將一個(gè)POJO注冊成一個(gè)service。消費(fèi)者bundle請求OSGI容器中基于某個(gè)特殊接口的注冊service。一旦找到,消費(fèi)者bundle就會綁定它,然后就可以調(diào)用service中的方法了。舉個(gè)例子會更容易說明。
導(dǎo)出services
1、確保com.howard.sample.HelloService里的MANIFEST.MF導(dǎo)入org.osgi.framework包 2、創(chuàng)建com.howard.sample.service.impl.HelloServiceActivator.java,代碼如下:
OK,我們就是用BundleContext的registerService方法注冊service的。這個(gè)方法需要三個(gè)參數(shù)。
3、最后一步就是修改HelloService的MANIFEST.MF文件,將Bundle-Activator改成com.howard.sample.service.impl.HelloServiceActivator
現(xiàn)在HelloService bundle已經(jīng)隨時(shí)準(zhǔn)備將HelloServiceImpl服務(wù)發(fā)布了。OSGI容器啟動HelloServie bundle的時(shí)候會讓HelloServiceActivator運(yùn)作,在那個(gè)時(shí)候?qū)elloServiceImpl注冊到容器中,接下來就是創(chuàng)建消費(fèi)者的問題了。
導(dǎo)入service
我們的消費(fèi)者就是HelloWorld bundle,主要修改的就是其中的Activator.java,修改代碼如下:
代碼很簡單,就不多說了。
在運(yùn)行之前我們在Run-->Run Configurations對話框里,把HelloWorld和HelloService這兩個(gè)bundle前面的鉤都打上。然后運(yùn)行時(shí)你會發(fā)現(xiàn)HelloServiceImpl.sayHello()方法已經(jīng)被調(diào)用了。
在OSGI控制臺輸入ss并回車,所有容器內(nèi)的bundle狀態(tài)一目了然。其中id為0的bundle是OSGI框架基礎(chǔ)bundle,另兩個(gè)就是HelloService和HelloWorld了,它倆的id是隨機(jī)的,狀態(tài)是ACTIVE也就是已啟動狀態(tài)。假設(shè)HelloService的id為7,HelloWorld為8。
輸入stop 8就可以暫停bundle的運(yùn)行,容器內(nèi)這個(gè)bundle還是存在的,只是狀態(tài)變成了RESOLVED。再次啟動使用start 8,然后就會看見HelloWorld bundle消費(fèi)了HelloService的服務(wù)。
創(chuàng)建服務(wù)工廠
剛才例子所示,我們會在HelloService bundle啟動時(shí)初始化并注冊service。然后不管存不存在消費(fèi)端,這個(gè)service都會存在,而且消費(fèi)端取得的service 實(shí)例其實(shí)都是同一個(gè)。OK,某些servie是比較耗費(fèi)資源的主,我們不希望它一直占用資源,最好是在真正用它的時(shí)候創(chuàng)建不用的時(shí)候銷毀就最好了。
解決如上問題的方案就是使用ServiceFactory接口的實(shí)現(xiàn)來代替原先service具體的實(shí)現(xiàn)到OSGI容器去注冊。這樣,以后只有當(dāng)其他bundle請求該服務(wù)時(shí),才會由ServiceFactory實(shí)現(xiàn)類來處理請求并返回一個(gè)新的service實(shí)例。
實(shí)例步驟如下: 1、在HelloService bundle創(chuàng)建一個(gè)實(shí)現(xiàn)ServiceFactory接口的類HelloServiceFactory類,代碼如下:
ServiceFactory接口定義了兩個(gè)方法:
2、修改HelloServiceActivator.java的start方法,將ServiceFactory作為服務(wù)注冊,代碼如下:
現(xiàn)在運(yùn)行下試試看,你會發(fā)現(xiàn)HelloWorld bundle啟動時(shí)才會初始化HelloService,控制臺會打印出"Number of bundles using service 1",當(dāng)HelloWorld bundle暫停時(shí)會打印出"Number of bundles using service 0"。
services跟蹤
某種情形下,我們可能需要在某個(gè)特殊的接口有新的服務(wù)注冊或取消注冊時(shí)通知消費(fèi)端。這時(shí)我們可以使用ServiceTracker類。如下步驟所示: 1、在HelloWorld bundle里的MANIFEST.MF導(dǎo)入org.util.tracker包。 2、創(chuàng)建HelloServiceTracker類,代碼如下:
我們在HelloServiceTracker的構(gòu)造函數(shù)里將HelloService接口名傳進(jìn)去,ServiceTracker會跟蹤實(shí)現(xiàn)這個(gè)接口的所有的注冊services。ServiceTracker主要有兩個(gè)重要方法:
3、修改Activator類,使用剛剛創(chuàng)建的HelloServiceTracker來獲取service:
現(xiàn)在運(yùn)行一下,可以發(fā)現(xiàn)只要HelloService bundle啟動或是暫停都會導(dǎo)致HelloServiceTracker的對addingService或removedService方法的調(diào)用。
ServiceTracker不僅僅能跟蹤Service的動向,它還能通過getService方法取得Service實(shí)例并返回。但是如果同一個(gè)接口下有多個(gè)service注冊,這時(shí)返回哪個(gè)service呢?這時(shí)候就需要看service的等級哪個(gè)高了。這個(gè)等級是service注冊時(shí)的property屬性里的一項(xiàng):SERVICE_RANKING。誰的SERVICE_RANKING高,就返回誰。 如果有兩個(gè)一樣高的呢?這時(shí)再看這兩個(gè)service誰的PID更低了。
如果對OSGI的ClassLoader機(jī)制有疑問,可以看看這篇解釋ClassLoader機(jī)制和自定義ClassLoader相關(guān)的文章: http://longdick.iteye.com/blog/442213
OSGI的基本原理和入門開發(fā)就到這里了。希望同學(xué)們能對OSGI開發(fā)有個(gè)簡單而清晰的認(rèn)識。
評論:
|
![]() |
|
Copyright © lainey | Powered by: 博客園 模板提供:滬江博客 |