簡介: 作為一個新的事實上的工業(yè)標(biāo)準(zhǔn),OSGi 已經(jīng)受到了廣泛的關(guān)注, 其面向服務(wù)(接口)的基本思想和動態(tài)模塊部署的能力, 是企業(yè)級應(yīng)用長期以來一直追求的目標(biāo)。Spring 是一個著名的 輕量級 J2EE 開發(fā)框架,其特點是面向接口編程和非侵入式的依賴注入。將 OSGi 和 Spring 結(jié)合能充分發(fā)揮二者各自的特長,更好地滿足企業(yè)級應(yīng)用開發(fā)的需求。Spring 開發(fā)組織在 2008 年發(fā)布了將 OSGi 和 Spring 結(jié)合的第一個版本:Spring-DM。本文通過一個簡單實例,介紹如何利用 Spring-DM 開發(fā)基于 OSGi 和 Spring 架構(gòu)的 Web 應(yīng)用,同時探討其中用到的關(guān)鍵技術(shù)及其基本思想。 發(fā)布日期: 2009 年 2 月 26 日
開發(fā)一個簡單的 OSGi Web 應(yīng)用實例 我們寫一個簡單的 Web 應(yīng)用 compute.html :計算兩個數(shù)字的和或乘積。如下圖所示: 圖 1. 一個簡單例子 ![]() 一個簡單例子.bmp 為了體現(xiàn) OSGi bundle 的動態(tài)部署能力,我們寫兩個 service bundle,其中一個計算兩個數(shù)字的和(稱為 add bundle),另外一個計算兩個數(shù)字的積(稱為 multiply bundle)。 當(dāng)我們點擊“Compute”按鈕的時候,如果此時 add bundle 被部署,則頁面將返回兩個數(shù)字的和,否則如果此時 multiply bundle 被部署,則頁面將返回兩個數(shù)字的積。
圖 2. 相關(guān)插件列表 ![]()
該應(yīng)用主要包含兩個層次: 服務(wù)層和 Web 層。Web 層基于 Spring-MVC 實現(xiàn),包含處理 Web訪問相關(guān)的 bundle(本例中只有一個)。服務(wù)層包含處理數(shù)字計算的 bundle,本例中包含一個聲明服務(wù)接口的 compute interface bundle 和兩個實現(xiàn)該服務(wù)接口的 bundle :add bundle 和 multiply bundle。基本模塊結(jié)構(gòu)如下圖所示: 圖 3. 基本框架 ![]() Step 1 :實現(xiàn) Service Layer 服務(wù)層的三個 OSGi bundle 實現(xiàn)完畢之后如下圖所示 : 圖 4. 服務(wù)層 ![]() 服務(wù)層.bmp 其中 com.zxn.example.service.compute 是聲明服務(wù)接口的 bundle。com.zxn.example.service.compute.add和 com.zxn.example.service.compute.multiply 是實現(xiàn)了服務(wù)接口的兩個 bundle。
聲明一個 Compute 接口,其中包含一個接口方法 computeNums(),如下圖所示 : 圖 5. 服務(wù)層接口 bundle ![]()
bundle com.zxn.example.service.compute.add 的基本程序結(jié)構(gòu)如下圖所示: 圖 6. 接口實現(xiàn) bundle :add ![]() 在該 add bundle 中,添加一個 Add 類,實現(xiàn) Compute 接口,如下圖所示: 圖 7. 接口實現(xiàn)代碼 :Add 類 ![]() 注意到我們在 META-INF 下建了一個 spring 目錄,并且添加了一個 computeAdd-context.xml 文件。系統(tǒng)啟動時,Spring 將利用該 xml 文件創(chuàng)建一個 bean 實例,并把該 bean 輸出為一個 OSGi service,如下圖所示 : 圖 8. Spring 聲明文件 :computeAdd-context.xml ![]() 該xml文件中,osgi : service是 Spring-DM 輸出 OSGi service 的標(biāo)記,其中的 interface屬性標(biāo)明了該 service 實現(xiàn)的服務(wù)接口。
按照與 add bundle 同樣的方法,實現(xiàn) multiply bundle,如下圖所示: 圖 9. 接口實現(xiàn)代碼:Multiply 類 ![]() 接口實現(xiàn)代碼-Multiply類.bmp 類似的,添加一個 computeMultiply-context.xml 輸出 OSGi service,如下圖所示 : 圖 10. Spring 聲明文件:computeMultiply-context.xml ![]() Web 層只包含一個 bundle:com.zxn.example.web,采用 Spring-MVC 和 OSGi 構(gòu)建,基本程序結(jié)構(gòu)如下圖所示: 圖 11. Web Layer 程序結(jié)構(gòu) ![]()
該JAVA類實現(xiàn)了 圖 12. 核心 servlet 類 ![]()
該 JAVA 類負責(zé)引用部署的 service bundle 完成最終計算,其中的 computeService 由 Spring 根據(jù) OSGi 中實際部署的 service 進行注入。本例中,實際部署的 service 可能是 add bundle 或者 multiply bundle。 需要特別注意的是,此處體現(xiàn)了 Spring-DM 的動態(tài)特性。OSGi 的動態(tài)部署能力使得 Spring 的動態(tài)服務(wù)注入成為可能。 圖 13. 服務(wù)消費類 ![]()
該 JAVA 類負責(zé)在 OSGi 環(huán)境中配置和注冊 HTTP 服務(wù),其關(guān)鍵方法為 bean 初始化時調(diào)用的 init( ) 方法。 圖 14. 在 OSGi 環(huán)境中注冊 HTTP 服務(wù) ![]() 該 init 方法中,第六行的 getHTTPService(…) 調(diào)用 OSGi 的 ServiceTracker 來獲取 OSGi環(huán)境中注冊的 HTTP 服務(wù)的引用,如下圖所示: 圖 15. 使用 ServiceTracker 獲取 HTTP 服務(wù) ![]()
該 xml 文件主要用于配置 HTTPContextResgistry bean 類,以及導(dǎo)入對 Compute 服務(wù)接口的引用。標(biāo)記 osgi : reference 用于聲明要導(dǎo)入的服務(wù)接口,其 interface 屬性標(biāo)明了該接口的定義,本例中為 com.zxn.example.service.compute.Compute 接口。 圖 16. Spring 聲明文件:導(dǎo)入服務(wù)接口 ![]()
該 xml 文件用于配置 ComputeControler bean類。 圖 17. Spring 聲明文件:配置核心 servlet 類 ![]() 以往開發(fā) J2EE 應(yīng)用通常需要將應(yīng)用服務(wù)器的 runtime 集成到開發(fā)環(huán)境中才能進行程序調(diào)試,非常麻煩。基于 OSGi 的應(yīng)用完全可以脫離應(yīng)用服務(wù)器運行,這使得程序開發(fā)和調(diào)試變得非常容易,直接在 Eclipse 中調(diào)試運行就可以。我們在 Eclipse 中將程序運行起來,如下圖所示: 圖18. 運行 OSGi 程序 ![]() 從上圖中看到,我們同時選擇部署了 add bundle 和 multiply bundle,利用 OSGi console 察看如下: 圖 19. 察看部署的 OSGi bundle ![]() 當(dāng) OSGi 環(huán)境中同時部署有多個服務(wù)接口的實現(xiàn) bundle 時,OSGi 會選擇一個默認(rèn)的 bundle提供服務(wù)。本例中,Spring 會默認(rèn)注入 add bundle。我們通過 web 訪問 compute.html 頁面: 圖 20. 訪問頁面 ![]() 點 Compute 按鈕之后,結(jié)果頁面如下: 圖 21. 訪問結(jié)果 ![]() 可以看出,是 add bundle 提供了計算服務(wù)。下面我們通過命令 <stop 76> 來停止 add bundle的服務(wù): 圖 22. 停止 add bundle ![]() 圖 23. add bundle 狀態(tài)變?yōu)?RESOLVED ![]() 重新訪問 compute.html 頁面,結(jié)果得到的是兩個數(shù)字的乘積。可以看出,是 multiply bundl 提供了計算服務(wù)。如下圖所示: 圖 24. 再次訪問頁面 ![]() |
|