作為一個新的事實上的工業標准OSGi 已經受到了廣泛的關注 其面向服務(接口)的基本思想和動態模塊部署的能力 是企業級應用長期以來一直追求的目標Spring 是一個著名的 輕量級 JEE 開發框架其特點是面向接口編程和非侵入式的依賴注入將 OSGi 和 Spring 結合能充分發揮二者各自的特長更好地滿足企業級應用開發的需求Spring 開發組織在 年發布了將 OSGi 和 Spring 結合的第一個版本SpringDM本文通過一個簡單實例介紹如何利用 SpringDM 開發基於 OSGi 和 Spring 架構的 Web 應用同時探討其中用到的關鍵技術及其基本思想
開發一個簡單的OSGi Web應用實例
一個簡單的 Web 應用
我們寫一個簡單的 Web 應用 l 計算兩個數字的和或乘積如下圖所示
圖 一個簡單例子

為了體現 OSGi bundle 的動態部署能力我們寫兩個 service bundle其中一個計算兩個數字的和(稱為 add bundle)另外一個計算兩個數字的積(稱為 multiply bundle) 當我們點擊Compute按鈕的時候如果此時 add bundle 被部署則頁面將返回兩個數字的和否則如果此時 multiply bundle 被部署則頁面將返回兩個數字的積開發環境准備
下載 Eclipse
獲取所有 OSGi Equinox 和 Spring 的插件 如下圖所示:


打開 Eclipse 設置 target platform 為上述插件集合
基本模塊設計
該應用主要包含兩個層次: 服務層和 Web 層Web 層基於 SpringMVC 實現包含處理 Web訪問相關的 bundle(本例中只有一個)服務層包含處理數字計算的 bundle本例中包含一個聲明服務接口的 compute interface bundle 和兩個實現該服務接口的 bundle add bundle 和 multiply bundle基本模塊結構如下圖所示
圖 基本框架

模塊程序實現
Step 實現 Service Layer
服務層的三個 OSGi bundle 實現完畢之後如下圖所示
圖 服務層

其中 comzxnpute 是聲明服務接口的 bundlecomzxnputeadd和comzxnputemultiply 是實現了服務接口的兩個 bundle
zxnpute
聲明一個 Compute 接口其中包含一個接口方法 computeNums()如下圖所示
圖 服務層接口 bundle

zxnputeadd
bundle comzxnputeadd 的基本程序結構如下圖所示
圖 接口實現 bundle add

在該 add bundle 中添加一個Add類實現Compute接口如下圖所示
圖 接口實現代碼 Add 類

注意到我們在 METAINF 下建了一個 spring 目錄並且添加了一個 computeAddcontextxml 文件系統啟動時Spring 將利用該xml文件創建一個 bean 實例並把該 bean 輸出為一個 OSGi service如下圖所示
圖 Spring 聲明文件 computeAddcontextxml

該xml文件中osgi : service是 SpringDM 輸出 OSGi service 的標記其中的 interface屬性標明了該 service 實現的服務接口
zxnputemultiply
按照與add bundle 同樣的方法實現 multiply bundle如下圖所示
圖 接口實現代碼Multiply 類

類似的添加一個 computeMultiplycontextxml 輸出 OSGi service如下圖所示
圖 Spring 聲明文件computeMultiplycontextxml
Step 實現 Web Layer
Web 層只包含一個 bundlecomzxnexampleweb采用 SpringMVC 和 OSGi 構建基本程序結構如下圖所示
圖 Web Layer 程序結構

ComputeControlerjava
該JAVA類實現了 orgspringframeworkwebservletmvcController是本 web應用中核心的 servlet負責接受並處理 web 請求該類調用 ComputeServiceRef 的方法實現業務邏輯該類關鍵的方法是 handleRequest(…) 如下圖所示
圖 核心 servlet 類

ComputeServiceRefjava
該 JAVA 類負責引用部署的 service bundle 完成最終計算其中的 computeService 由 Spring 根據 OSGi 中實際部署的 service 進行注入本例中實際部署的 service 可能是 add bundle 或者 multiply bundle
需要特別注意的是此處體現了 SpringDM 的動態特性OSGi 的動態部署能力使得 Spring 的動態服務注入成為可能
圖 服務消費類

HTTPContextResgistryjava
該 JAVA 類負責在 OSGi 環境中配置和注冊 HTTP 服務其關鍵方法為 bean 初始化時調用的 init( ) 方法
圖 在 OSGi 環境中注冊 HTTP 服務

該 init 方法中第六行的 getHTTPService(…) 調用 OSGi 的 ServiceTracker 來獲取 OSGi環境中注冊的 HTTP 服務的引用如下圖所示
圖 使用 ServiceTracker 獲取 HTTP 服務

computeWebcontextxml
該 xml 文件主要用於配置 HTTPContextResgistry bean 類以及導入對 Compute 服務接口的引用標記 osgi : reference 用於聲明要導入的服務接口其 interface 屬性標明了該接口的定義本例中為 comzxnputeCompute 接口
圖 Spring 聲明文件導入服務接口

computeWebDispatcherxml
該 xml 文件用於配置 ComputeControler bean類
圖 Spring 聲明文件配置核心 servlet 類

運行程序
以往開發 JEE 應用通常需要將應用服務器的 runtime 集成到開發環境中才能進行程序調試非常麻煩基於 OSGi 的應用完全可以脫離應用服務器運行這使得程序開發和調試變得非常容易直接在 Eclipse 中調試運行就可以我們在 Eclipse 中將程序運行起來如下圖所示
圖 運行 OSGi 程序

從上圖中看到我們同時選擇部署了 add bundle 和 multiply bundle利用 OSGi console 察看如下
圖 察看部署的 OSGi bundle

當 OSGi 環境中同時部署有多個服務接口的實現 bundle 時OSGi 會選擇一個默認的 bundle提供服務本例中Spring 會默認注入 add bundle我們通過 web 訪問 l 頁面
圖 訪問頁面

點 Compute 按鈕之後結果頁面如下
圖 訪問結果

可以看出是 add bundle 提供了計算服務下面我們通過命令 <stop > 來停止 add bundle的服務
圖 停止 add bundle

圖 add bundle 狀態變為 RESOLVED

重新訪問 l 頁面結果得到的是兩個數字的乘積可以看出是 multiply bundl
提供了計算服務如下圖所示
圖 再次訪問頁面

小結
作為當前頗具生命力的兩個標准和框架OSGi 和 Spring 已經初步融合在一起二者的結合為開發企業級的 Web 應用同時提供了巨大的靈活性和動態部署能力本文通過一個簡單的例子描述如何開發一個基於 OSGi 和 Spring 的 Web 應用並說明了開發過程中涉及到的技術關鍵點
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19601.html