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