在Spring DM中使用Annotations發布和引用OSGi服務
Spring DM并不是OSGi規范的實現,也就是說它不是OSGi容器。它只是一套用于在 OSGi環境中將Spring Bean注冊發布為OSGi服務的工具。它充分利用Spring的特性,將OSGi與Spring無縫的加以結合,實現了Spring的模塊化開發。
1. 在使用Spring DM進行開發過程中發現的問題:
雖然Spring DM改進了OSGi原本的DS開發,使用Spring Bean來完成服務的注冊。但是對于“懶惰”的程序員來說還是太過繁瑣,首先需要在XML中注冊SpringBean,然后要使用SpringDM提供的 特殊命名空間(
當然Spring DM的開發團隊也想到了這點,為我們開發人員提供了Annotation的選項,這樣可以大大減少XML的配置量(這里我們不爭論XML和 Annotation孰優孰劣)。但是不知為何,Spring DM只提供了引入服務的Annotation,并沒有提供發布OSGi服務的Annotation,這讓我很費解?其次,由于SpringDM是在 JDK1.4環境下編譯的,所以默認情況下Annotation的功能是Disabled的。這又讓我很費解?到底讓我們用不用Annotation!
2. 問題的解決方案:
針對上述的問題,我們可以通過以下方法解決;
1) 如何啟用Spring DM的Annotation功能
通過閱讀Spring DM提供的官方文檔,讓我很莫名,關于Annotation的介紹只有寥寥數語,而且還是放在附錄中介紹的。可能是我的英文水平太爛,總之一句話,沒看 懂!后來從解決其他問題的過程中得到了啟示,終于開啟了SpringDM的Annotation功能。
第一步,創建一個Fragment類型的Bundle,具體的目錄結構如下圖所示:
這里主要關注2個文件,一個是extender.xml文件和MANIFEST.MF文件。
第二步,創建extender.xml文件:
在上圖所示的目錄結構中創建一個extender.xml文件,這個文件用于覆蓋SpringDM Extender的配置選項。因為默認情況下是不支持Annotation的,所以要將指定的屬性值設置為開啟狀態,才能使用Annotation功能。 配置文件的內容如下:
這個配置文件其實就是一個Spring Bean的配置文件。將process.annotations屬性設置成true,就開啟了Spring DM的Annotation功能。
第三步,創建MANIFEST.MF文件,這個文件是Bundle的屬性配置文件,我們在這個文件中指定Fragment-Host屬性,具體內容如下:
其中我們要關注的是Fragment-Host屬性,這里指定為 org.springframework.osgi.extender,表示在extender Bundle啟動之前先啟動ftps-extender-config這個Bundle,這樣就將默認的屬性值更新為我們設置的屬性值。
第四步,在Spring的XML配置文件中注冊處理Annotation的處理器Bean,如下所示:
通過上述4個步驟,我們就開啟了Spring DM的Annotation功能。
以下例子展示如何使用Spring DM的Annotation功能:
其中@ServiceReference就是引入OSGi服務的Annotation,它等效于XML中的
2) 編寫自己的Annotation實現OSGi服務的發布:
勝利的喜悅還沒維持多久,新的問題又隨之而來。既然我們已經有引入OSGi服務的Annotation,為什么發布OSGi服務的時候不能使用 Annotation呢?我們仍然在繼續編寫一大坨苦澀的OSGi配置項,這種工作即枯燥又乏味。但是尋遍SpringDM的所有官方文檔,包括 SpringDM提供的Annotation擴展包源代碼,都沒有找到發布OSGi服務的Annotation。Google一下,大致都是提問的,沒有 回答問題的。沒有辦法,只能靠自己。經過對SpringDM源代碼的閱讀以及使用BEBUG來查看代碼流程的走向,終于了解了SpringDM將 Spring Bean發布為OSGi服務的大致方法。其中最關鍵的對象就是:OsgiServiceFactoryBean。這個工廠bean就是將 SpringBean發布為OSGi服務的關鍵類。這個類并不難懂,有興趣的朋友可以閱讀一下這個類的源代碼。由于我們是解決問題的文章,不是談理論的文 章,所以我們繼續看實現方案:
首先介紹一下解決方案的大致流程。1)通過編寫一個實現了BeanPostProcessor接口的處理器類,我們就可以對Bean的生命周期進行 控制。2)在容器中的某個Bean被初始化之后,我們攔截這個Bean,并獲取該Bean上是否寫了注冊OSGi服務的Annotation。3)如果 是,則實例化OsgiServiceFactoryBean對象,設置相關的屬性值,并調用OsgiServiceFactoryBean對象的 afterPropertiesSet方法,進行OSGi服務的注冊和發布。最后返回該OsgiServiceFactoryBean對象。同時將該對象 的引用放入一個集合中保存用于OSGi服務的注銷。4)當處理器類被銷毀時,對集合中的所有OsgiServiceFactoryBean對象執行 destroy方法,完成OSGi服務的注銷操作。
先來看Annotation的代碼,很簡單,如下所示:
ElementType.TYPE指定這個Annotation只能用于類聲明,接口聲明上。
接著是處理器的實現代碼,先關注類簽名:
這里需要關注的是實現的幾個接口的用途。實現BundleContextAware接口是為了在處理器中獲取Bundle上下文對象。實現 BeanClassLoaderAware接口是為了在處理器中獲取ClassLoader對象,這些對象都是注冊發布OSGi服務所必須使用的對象。而 繼承InstantiationAwareBeanPostProcessorAdapter適配器是為了在Spring Bean初始化完之后給我們一個機會進行定制的特殊處理。我們需要覆蓋的是 InstantiationAwareBeanPostProcessorAdapter類的 postProcessAfterInitialization方法。該方法在Spring Bean初始化之后執行。我們來看這個方法的實現,如下所示:
代碼中的注釋已經很好的說明了各邏輯塊的實現目的,不再贅述。其中需要關注createExporter方法,這個方法是創建OsgiServiceFactoryBean對象的。如下所示:
代碼很簡單,就是實例化對象,并調用注冊發布OSGi服務的方法。其實發布一個OSGi服務只需要三個參數:Bean名稱,Bean對象,Bean實現接口類型的數組,這個和XML中的配置屬性一一對應:
其中ref屬性對應Bean名稱以及一個Bean對象的引用,interface屬性對應Bean實現接口類型的一個數組。
該方法中用到的一些其他實例變量的定義如下:
最后來看一下OSGi服務的注銷實現,代碼如下:
注銷服務就是將先前注冊時保存下來的OsgiServiceFactoryBean對象集合進行destroy方法的調用。
3. 啟用發布OSGi服務的Annotation:
相比較開啟SpringDM自帶的Annotation,我們這個Annotation的啟用方法要簡單的多。只要在Spring的XML中注冊這個處理器Bean就可以了,代碼如下:
以下實例代碼展示了如何使用使用Annotation發布一個OSGi服務發布:
其中@OsgiService就是注冊發布OSGi服務的Anntation。到此我們終于實現了使用Annotation來發布注冊OSGi服務 以及引入OSGi服務,我們不再需要在XML中配置那一大坨無聊的OSGi服務配置了。最后引用一句名言:任何發明創造源自于“懶惰”。
轉自:CSDN。