Spring-OSGi 到底是怎麼回事?

工程 | Costin Leau | 2007年4月5日 | ...

歡迎來到我的部落格!這是我的第一篇博文...有史以來第一篇。我一直努力剋制寫部落格的衝動,但既然這麼多人鼓勵我寫寫我在 i21 的工作,我決定試一試。此外,還有一個原因,就是 Spring-OSGi 昨晚(東歐時間)釋出了第一個 版本

我從去年八月就開始參與 Spring-OSGi 專案了,這段經歷相當不錯。這是我做過的最具挑戰性的專案之一,我很高興它能向公眾釋出,哪怕只是一個里程碑版本。非常感謝所有參與其中的人促成了這一切,特別是我的 團隊 夥伴——Adrian、Andy 和 Hal!

在這篇博文中,我想讓您對 Spring 1.0 M1 目前提供的內容有個大致瞭解;我將跳過介紹 OSGi,因為網際網路上有很多優秀的資料(見底部的連結)。

Spring-OSGi 背後的基本思想是讓在 OSGi 環境中構建/編寫/部署 Spring 應用程式變得容易。也就是說,讓 Spring 提供的全面的基於 POJO 的程式設計模型(IoC、AOP、服務抽象)在注重版本控制和模組化的動態執行環境中透明地工作。

採用 OSGi 時最大的挑戰之一是處理其動態特性。服務(它們是簡單的物件例項)可能會出現或消失,您的應用程式必須處理這種情況。解決方案並不直接,因情況而異,並且需要像異常處理和事務處理一樣應用範圍內的考慮。上述模組化強制執行的類載入限制,結合 AOP,可能會導致很多麻煩,並迫使開發人員進行變通,從而丟棄 OSGi 帶來的好處。這些只是我們在 Spring-OSGi 中正在解決的一些少數問題示例,最終應該能夠讓採用 OSGi 的過程更加順暢。

讓我們看看您在 1.0 M1 中會發現的一些功能

  1. OSGi 應用上下文

OSGi 基於 bundles(捆綁包),它們不過是帶有特定清單條目的 Jar 檔案。它們是模組,是匯出和匯入類包和/或服務的單元。一個應用程式可以由一個或多個捆綁包組成。Spring-OSGi 提供了一個基於捆綁包及其生命週期的應用上下文,讓您可以訪問應用程式所在的 OSGi 上下文、一個 OSGi 自定義 作用域以及一個 額外的 Aware 介面。與其他同類介面一樣,該介面提供了進行依賴查詢的能力,但在使用之前您應該三思,因為 OSGi 服務依賴注入已得到充分支援。

  1. 資源抽象

在 OSGi 中,類載入已與以前不同了——例如,classpath 有了不同的含義,因為它可以由多個捆綁包組裝而成(而這些捆綁包又可以在多個 classpath 中使用)。因此,getClass().getResource() 可能會產生不同的結果,因為執行環境已經發生了很大的變化。下面是一個尋找類時可能得到的結果示例:

Equinox: bundleentry://5/my/package/MyClass.class(也可以是 bundleresource://Knopflerfish: bundle://13/my/package/MyClass.class Felix: bundle://18.0/0/my/package/MyClass.class

依賴 URL scheme(方案)是不可移植的,因此 Spring OSGi 最先做的事情之一就是透過簡單而有效的 Resource 介面封裝低階訪問,這樣無論您使用哪種 OSGi 實現,都可以找到您的檔案。此外,模式風格的查詢(如 myFolder/*)也是可能的(實際上我們使用 /META-INF/spring/* 來檢測“spring powered”捆綁包)。

  1. 動態服務支援

假設您有以下應用上下文


<!-- service layer-->
<bean id="myService" class="ServiceClass">
    <property name="dao" ref="dao"/>
</bean>

<!-- dao layer -->
<bean id="dao" class="poorPerformerDAO">
    <property name="dataSource" ref="someDataSource"/>
</bean>

大多數應用程式都有多個層,這些層非常適合作為 OSGi 捆綁包,因為您可以簡單地將 DAO 類放在一個捆綁包(dao 捆綁包)中,將服務層放在另一個捆綁包(service 捆綁包)中,這樣當 DAO 實現更新時(例如上面的 poorPerformerDAOexcellentPerformerDAO 替換),或者部署不同版本的應用程式時,無需重新啟動應用程式:這是選擇 OSGi 的最佳理由之一!

然而,要利用 OSGi 的能力,物件必須成為服務——也就是說,它們必須在“消費”之前註冊到 OSGi 平臺,而消費者(客戶端)必須查詢它們。這是一種類似於 SOA 的方法,可以避免模組之間的緊密耦合,因此當一個捆綁包關閉時,由它釋出的服務就會消失。這意味著首先必須使用 OSGi API 進行註冊和查詢,而且還必須處理服務可能出現或消失帶來的故障。

Spring-OSGi 在這方面提供了很大的幫助,它允許幾乎任何型別的物件在您的應用程式中匯出和匯入,而無需任何程式碼更改。

服務捆綁包


<!-- service layer-->
<bean id="myService" class="ServiceClass">
    <property name="dao>
       <osgi:reference interface="daoInterface"/>
    </property>
</bean></code>

Dao 捆綁包


<!-- dao layer -->
<bean id="dao" class="goodPerformerDAO">
    <property name="dataSource" ref="someDataSource"/>
</bean>

<osgi:service ref="dao"/>

使用 Spring-OSGi 適應 OSGi 環境,需要新增兩行配置

  1. 用於指示框架查詢哪些 OSGi 服務
  2. <li><span style="font-family:courier"><osgi:service ..></span> to export an existing bean as an OSGi service</li>
    

顯然,對於 dataSource 依賴也可以這樣做——將其外部化到一個 OSGi 捆綁包中,然後只需將普通的 ref 替換為 osgi:reference。無需處理新的 API,無需處理 try/catch/finally 的異常,特別是內建的查詢行為。可以配置 Spring-OSGi,以便只有在找到實現 daoInterface 的服務時才啟動應用上下文——也就是說,可以滿足 dao 依賴。此外,在執行時,如果服務消失,Spring-OSGi 將根據您的配置(重試次數和超時)自動尋找新的實現:如果在擁有該 bean 的捆綁包更新時(例如將 goodPerformerDAO 升級到 excellentPerformerDAO)恰好呼叫了 'dao' bean 上的方法,您不會收到一個令人討厭、顯然無法解釋的異常,而是會感受到一個因查詢新服務而引起的微不足道的延遲。一如既往,此行為是完全可配置的。

在某種程度上,匯出器/匯入器功能類似於 Spring remoting,但主要的區別在於它不涉及遠端呼叫——所有內容都在同一個 JVM 中執行,並且完全不涉及序列化。

  1. 整合測試

測試很重要(甚至至關重要),特別是在將應用程式遷移到新環境時,因為許多被認為是理所當然的事情可能會失敗:我們在開發初期就親身體驗了這一點。這是一個大問題,因為談到 OSGi 時,測試絕非易事或自動化,因為執行環境(如果您願意,可以稱之為 OSGi 平臺或容器)必須啟動(沒有標準化 API)並進行設定(安裝您的測試依賴的捆綁包)。然而,棘手的部分在於測試本身必須 OSGi 化——放置在一個宣告依賴關係的清單旁邊,成為一個必須安裝並啟動到 OSGi 平臺中的捆綁包。

認識 AbstractOsgiTests其夥伴


public class SimpleIntegrationTests extends AbstractConfigurableBundleCreatorTests
{

  public void testInstalledBundles() {
    // get access to the OSGi bundle context
     Bundle[] bundles = getBundleContext().getBundles();

     getBundleContext().installBundle(someBundleLocation);
     assertEquals(bundles.length()+1, getBundleContext().getBundles().length());
  }

  // specify the bundles to install  
  protected String[] getBundles() {
        return new String[] {
                "org.springframework.osgi, commons-collections.osgi, 3.2-SNAPSHOT",
                "org.springframework.osgi, org.springframework.osgi.test.simple.service,1.0-SNAPSHOT"};
    }
}

AbstractOsgiTests 構建在 JUnit 之上,因此您可以直接從 IDE 中編寫和執行 OSGi 整合測試。整個設定由測試基礎設施處理,您無需操心:無需為測試編寫 MANIFEST.MF 檔案,無需進行任何打包或部署——一切都自動處理。而且它速度很快,非常快!實際上,只有不到 10% 的啟動時間花在 Spring-OSGi 程式碼內部——其餘時間由 OSGi 平臺本身使用。我們的大多數整合測試都在 1-3 秒內完全執行。Equinox、Knopflerfish 和 Felix 都支援。

嗯,我覺得第一篇博文就寫到這裡吧... 今後的博文我會寫更多關於 Spring-OSGi 功能的內容。希望我已引起您的興趣,讓您想試試 1.0 M1(請注意這是第一個里程碑版本,還有一些“不足之處”)。

感謝閱讀!Costin

OSGi Alliance 提供了一些不錯的 入門白皮書 維基百科 EclipseCon OSGi 專題 Spring-OSGi 規範 Javapolis 2006 關於 Spring-OSGi 的 演講(由本人主講) 最後,但同樣重要的是,老朋友 Google

獲取 Spring 郵件通訊

訂閱 Spring 郵件通訊,保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您飛速進步。

瞭解更多

獲取支援

Tanzu Spring 透過一份簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

近期活動

檢視 Spring 社群所有近期活動。

檢視全部