上1篇博文中我們編寫了第2個(gè)簡(jiǎn)單的osgi的example,并編寫了1個(gè)接口DictionaryService,并在Activator這個(gè)Bundle中實(shí)現(xiàn)了這個(gè)interface,并在start啟動(dòng)方法中進(jìn)行了osgi服務(wù)的注冊(cè),但并沒有使用這個(gè)服務(wù),這1篇文章中其實(shí)不講授怎樣使用這個(gè)已注冊(cè)的服務(wù),但是會(huì)講授服務(wù)的使用方式,1種為聲明式服務(wù),1種為傳統(tǒng)注冊(cè)式服務(wù),以下就是開始講授作甚osgi的注冊(cè)式服務(wù)與聲明式服務(wù)。
傳統(tǒng)方式下,我們注冊(cè)服務(wù)都是在bundle的激活器(Activator)中使用BundleContext.registerService()方法完成的。而服務(wù)的獲得需要通過BundleContext.getServiceReference()獲得ServiceReference實(shí)例,進(jìn)而使用BundleContext.getService()得到真實(shí)的服務(wù)實(shí)例。這類方式雖然能夠完成服務(wù)的發(fā)布與使用,但是帶來1定的問題,具體以下:
產(chǎn)生較多的樣板式代碼。OSGi的bundle是動(dòng)態(tài)化的,伴隨著bundle的安裝和卸載,它所發(fā)布的服務(wù)也會(huì)動(dòng)態(tài)地處于可用或不可用的狀態(tài),因此每次使用服務(wù)的時(shí)候,我們都需要借助BundleContext對(duì)象去服務(wù)注冊(cè)中心查找,而不能通過1次查找,1勞永逸地持有服務(wù)對(duì)象的援用。雖然有ServiceListener和ServiceTracker幫助我們監(jiān)聽和跟蹤服務(wù)的狀態(tài),但是整體而言這類方式較為繁瑣且容易出錯(cuò)。
影響啟動(dòng)時(shí)間,服務(wù)在激活器中注冊(cè)時(shí),需要實(shí)例化所有要發(fā)布的服務(wù)對(duì)象,由于激活器的start()方法是同步調(diào)用的,所以會(huì)影響到全部利用的啟動(dòng)時(shí)間。
加大內(nèi)存的占用,在激活器中注冊(cè)服務(wù)時(shí),我們需要實(shí)例化所有的服務(wù)對(duì)象,但是這些服務(wù)在利用運(yùn)行期間,其實(shí)不1定會(huì)用到,這在無形中加大了內(nèi)存的占用。
API依賴引發(fā)的平臺(tái)侵入性。使用傳統(tǒng)方式注冊(cè)和使用服務(wù),會(huì)用到大量的OSGi API,從而產(chǎn)生與OSGi平臺(tái)的耦合,如果要將代碼復(fù)用到非OSGi場(chǎng)景當(dāng)中,需要較多的重構(gòu)工作。
osgi是通過聲明式服務(wù)來解決以上存在的問題的,聲明式服務(wù)中引入了兩個(gè)元素,構(gòu)件(component)和元數(shù)據(jù)文件(metadata.xml)。構(gòu)件是1個(gè)物理的、可替換的系統(tǒng)組成部份,它包裝了實(shí)現(xiàn)體且提供了對(duì)1組服務(wù)接口的實(shí)現(xiàn)方法。構(gòu)件本身必須相容于接口且實(shí)現(xiàn)接口,接口表示了駐留在構(gòu)件內(nèi)的成份所實(shí)現(xiàn)的服務(wù)。這些服務(wù)定義了的1個(gè)整合的行動(dòng),并從1些構(gòu)件實(shí)例提供給其它客戶端構(gòu)件實(shí)例。在聲明式服務(wù)中1個(gè)構(gòu)件就對(duì)應(yīng)了某1個(gè)構(gòu)件實(shí)現(xiàn)類,這個(gè)類相當(dāng)因而1個(gè)pojo(普通的Java對(duì)象),在這個(gè)類中我們可以注冊(cè)服務(wù)、援用服務(wù)、構(gòu)件屬性配置等1些滿足特定需求的操作,總之構(gòu)件是服務(wù)的提供者和使用者。而元數(shù)據(jù)文件則是1個(gè)xml文件,在聲明式服務(wù)中所有的元數(shù)據(jù)文件名稱都為metadata.xml,在這個(gè)xml文件中我們可以根據(jù)需求配置構(gòu)件的1些必須信息,且所配置的這些信息必須遵守聲明式服務(wù)元數(shù)據(jù)規(guī)范。
聲明式服務(wù)主要由4個(gè)部份組成,聲明式服務(wù)容器部份、元數(shù)據(jù)解析部份、代碼織入部份和打包成聲明式服務(wù)bundle的插件部份。
這篇文章講授了傳統(tǒng)的注冊(cè)式服務(wù)和聲明式服務(wù),注冊(cè)式服務(wù)在前面1篇的博文中有所提及,在后文中還是有相應(yīng)的使用,但在聲明式服務(wù)上,后文中將會(huì)使用blueprint來代替,Blueprint規(guī)范來源于Spring Dynamic Modules項(xiàng)目,最早出現(xiàn)于R4.2企業(yè)規(guī)范當(dāng)中。這個(gè)到了往后講授blueprint的時(shí)候再具體講授這些。