完善全貌:Spring、OSGi 和 SpringSource 應用平臺

工程 | Adrian Colyer | 2008 年 5 月 1 日 | ...

** 5 月 2 日更新了案例研究:- 詳情請參見本文底部 ** 我相信大多數閱讀此部落格的人都已看到昨天 SpringSource 應用平臺的釋出公告。如果還沒有,請務必檢視 Rob 的部落格文章,其中描述了一些動機、程式設計模型和路線圖。

有兩個常見問題我希望在此篇文章中立即解答。之後,我將描述另外兩個令人興奮的公告,它們與 SpringSource 應用平臺本身相輔相成,但昨天並未佔據頭條:SpringSource 企業 Bundle 倉庫和用於 Eclipse 的應用平臺工具。它們共同完善了圍繞基於 OSGi 的企業應用開發與 Spring 的整個故事。

過去 24 小時內我多次聽到的問題是:OSGi 有什麼問題 - 為什麼我們不能直接使用純淨的 OSGi 服務平臺(例如 Equinox、Felix 或 Knopflerfish),而非 SpringSource 應用平臺?

OSGi 絕對沒有任何問題。

OSGi 是一個出色的基礎和服務平臺 - 這也是我們和許多其他方選擇在其基礎上構建的原因。它已在廣泛的行業和應用中得到驗證,並且支撐著像 Eclipse 和 IBM 的 WebSphere 等應用,以及其他幾家供應商的中介軟體棧。

直接使用 OSGi 規範 API 進行程式設計缺乏一些我們對企業應用所期望的特質 - 例如使用依賴注入的能力以及在容器外部輕鬆進行單元和整合測試的應用建立能力。直接使用 OSGi 規範 API 進行程式設計還迫使您在相對較低的層級處理 OSGi 平臺的動態性 - 當您依賴的模組和服務在執行時停止、啟動、安裝和更新時,您會怎麼做?但這裡沒有根本性的障礙,我們無法透過 Spring Dynamic Modules 專案克服這些障礙。使用 Spring Dynamic Modules 構建的應用可以在任何標準的 OSGi 服務平臺上執行,並且我們針對 Equinox、Felix 和 Knopflerfish 測試了所有構建。我們致力於確保 Spring Dynamic Modules 和基於 Spring 的程式設計模型保持執行時中立。這個立場不會因為 SpringSource 應用平臺的引入而改變。

現有的企業庫也絕對沒有任何問題。

嗯,好吧。確實有一些情況不盡如人意,但總體而言,我們知道如何讓它們滿足企業應用開發的需求。

那麼問題出在哪裡呢?

如果 OSGi 工作得很好,並且現有的企業庫也滿足我們的需求,那麼問題出在哪裡?困難在於嘗試將 OSGi 服務平臺與一組未考慮 OSGi 而編寫的現有企業庫結合時。這不是 OSGi 的錯,它擁有一個出色的模型,提供了卓越的模組化、版本控制和操作控制。也不是企業庫的錯 - 它們並不是為在 OSGi 下執行而編寫的。但正是那些讓 OSGi 如此吸引人的特性打破了那些企業庫開發者所做的假設。例如,OSGi 的模組化模型阻止你檢視其他 Bundle 的私有部分。這正是你想要的,直到你意識到你的企業庫無法再看到你的應用型別。許多東西都可能崩潰:從 commons logging 到 jsps,從標籤庫到資料來源,從載入時織入到元件掃描,從資源載入到 orm 對映。不勝列舉……(是的,當你將應用程式碼和它所需的所有庫打包到一個 Bundle 中時,你可以讓這些東西中的許多工作,但這很大程度上偏離了重點!)。

這就是為什麼你會看到許多人在 OSGi 之上構建,但很少將 OSGi 的好處傳遞到應用程式設計模型中(Eclipse RCP 是一個罕見的例外)。當你在 OSGi 之上構建,但不一定將該模型暴露給終端使用者應用開發時,你可以按照 OSGi 模型構建並使其工作。當你需要提供一個平臺,在該平臺上可以使用大量的現有企業庫時,情況就不同了。如果我們能拋棄所有這些,從頭開始使用專門為 OSGi 編寫的庫,我們會沒問題。例如,我們確保了 Spring Framework 完全能夠在 OSGi 服務平臺內部執行。但這並非現實可行的提案。或者,我們可以等待現有庫的開發者將它們全部轉換以在 OSGi 下開箱即用(就像我們對 Spring 所做的那樣)。但除非其他人都這麼做,否則他們這樣做的動機是什麼?所以我們似乎陷入了先有雞還是先有蛋的困境。這是 OSGi 企業專家組在過去一年中花費大量時間討論的問題。SpringSource 應用平臺解決的正是這個問題:- 透過使具有標準 OSGi 語義的標準 OSGi Bundle 與現有企業應用庫協同工作,從而將企業應用開發引導到 OSGi 的世界中。

我還要再次強調,該平臺不僅僅是關於 OSGi:OSGi 支援是我們最興奮的特性之一,但 SpringSource 應用平臺也是一個出色的伺服器平臺,用於部署標準的 war 檔案。我們將在後續文章中描述該平臺在這種場景下提供的優勢。

希望這篇文章有助於澄清圍繞 SpringSource 應用平臺與 OSGi 之間關係的困惑。如果您一直關注到這裡,可能已經注意到了另一個潛在的問題:讓現有企業庫在 OSGi 下工作固然不錯,但您是否需要將它們所有的 jar 檔案都轉換為 OSGi Bundle 才能部署它們呢?是的,您需要。事實證明,如果您想正確地對所有匯入和匯出進行版本控制並確保具有正確的符號名稱等,這將是一項大量的工作。好訊息是,對於數百個常用的企業應用庫,我們已經為您完成了艱苦的工作,並在 SpringSource 企業 Bundle 倉庫中提供了 OSGi 就緒的版本...

SpringSource 企業 Bundle 倉庫

SpringSource 企業 Bundle 倉庫既是一個可供 Ivy 和 Maven 使用的倉庫,也是一個線上可搜尋的企業庫資料庫。您可以在 www.springsource.com/repository 找到它。您可以按名稱瀏覽 Bundle,或者只需輸入搜尋詞即可查詢名稱、匯出的包、類或資源匹配的 Bundle。您還可以檢視任何 Bundle 的最小(僅滿足必需依賴項)和最大(滿足儘可能多的可選依賴項)傳遞依賴項。

摘自常見問題解答

"SpringSource 企業 Bundle 倉庫是使用 Spring Framework 開發企業 Java 應用常用的開源庫集合。倉庫包含 jar 檔案 (Bundle) 和庫定義 (".libd") 檔案。庫定義了一組 Bundle,這些 Bundle 通常會為了某個目的(例如 "Spring Framework" 庫)一起使用。倉庫中包含數百個 Bundle。" 該倉庫滿足以下條件:

  • 倉庫中的每個 jar 檔案都是一個有效的 OSGi Bundle。您從倉庫下載的任何 jar 都可以原樣部署到 OSGi 服務平臺和 SpringSource 應用平臺中。它也可以在 OSGi 外部作為常規 jar 檔案使用。
  • 每個 Bundle 和庫都關聯著完整的版本資訊。Bundle 的包匯出資訊包含版本資訊,Bundle 的包匯入資訊包含完整的版本範圍相容性資訊。
  • 倉庫是傳遞完整的。任何 Bundle 的強制依賴項保證也在倉庫中。倉庫中任何 Bundle 的大多數可選依賴項也都會存在。任何庫定義中列出的 Bundle 保證在倉庫中。
  • 倉庫是自洽的。在任何構件上傳到倉庫之前,我們都會驗證它是否可以與倉庫中所有其他 Bundle 一起安裝、解析並在 OSGi 服務平臺中啟動(使用與 SpringSource 應用平臺相同的配置檔案)。
  • 倉庫可用於基於 Ivy 和 Maven 的構建。
為了維護這些保證,我們圍繞構件釋出到倉庫制定了治理模型。有一個 JIRA 例項,您可以針對該例項提出包含其他庫的請求,並報告現有已釋出構件的任何問題(與 OSGi manifest 等相關)。

應用開發工具

到目前為止,我們已經討論了用於將應用開發為 OSGi Bundle 的基於 Spring 的程式設計模型,用於部署到 OSGi 服務平臺的企業庫的可用性,以及一個能夠讓這些傳統庫在 OSGi 執行時中工作的執行時(SpringSource 應用平臺)。拼圖缺失的部分是使基於 OSGi 的應用建立變得容易的開發者工具。

Eclipse 已經內建了 OSGi 開發工具。由於每個 Eclipse 外掛也是一個 OSGi Bundle,因此 Eclipse PDE 工具(外掛開發環境工具)可以用於 OSGi 應用開發。然而,這些工具主要設計用於開發 Eclipse 外掛這一事實顯而易見,在使用它們進行 OSGi 應用開發時存在一些常見的令人沮喪的地方。一個問題是 META-INF/MANIFEST.MF 檔案只能放在專案的根目錄下 - 這與 Ivy 和 Maven 等構建工具配合得不好;另一個問題是您整個工作空間只能受限於一個目標平臺(用於開發的 Bundle 集合)。PDE 工具真正出色的地方,也是您真正需要的,是它們從 OSGi manifest 構建專案的編譯類路徑 - 這樣在編譯、測試和執行時之間就不會出現類路徑和類可見性的差異。

與 SpringSource 應用平臺一起,我們還發布了一套 Eclipse 外掛(可從 SpringSource 應用平臺下載頁面獲取),這些外掛使得 OSGi 應用的開發更加容易,特別是針對 SpringSource 應用平臺的應用。您的 META-INF/MANIFEST.MF 檔案可以位於任何源目錄中,並且這些工具從 manifest 條目構建編譯類路徑。然而,您可以將您的專案與定義到 Eclipse 的 SpringSource 應用平臺伺服器關聯(使用 WTP 功能),而不是單個目標平臺。然後,您專案的類路徑將從您 manifest 檔案中的匯入語句派生,針對您工作空間中的其他 Bundle 專案以及關聯伺服器中安裝的 Bundle 進行解析。您在編譯時獲得的類路徑和依賴項的解釋與您在執行時獲得的完全相同。當然,正常的“部署到伺服器”選項也有效。

這是伺服器在 Eclipse 內部執行時的情況:

此截圖顯示瞭如何使用“Bundle Dependencies”類路徑容器管理類路徑。請注意,您未在 manifest 檔案中匯入的包被灰顯,表示您當前無法訪問它們。

更好的是我們如何能夠利用 OSGi 的模組化。一組專案(每個 Bundle 一個)構成了您的應用。當您更改專案中的任何內容時,額外的增量構建器會分析資源差異,並對 SpringSource 應用平臺中正在執行的 Bundle 進行即時更新 - 因此您始終執行的是最新程式碼:每一次,始終如此。這極大地提高了生產力,並提供了出色的開發體驗。

案例研究

Matt Raible 釋出了一篇題為部落格文章,講述了他嘗試在使用 Freemarker 的情況下,在沒有使用 SpringSource 應用平臺的情況下,讓 Spring Web 應用在 OSGi 下工作的冒險經歷。這似乎是一個很好的挑戰性應用,可以測試我上面關於讓現有企業庫工作所說的話。好訊息是,這個應用在 SpringSource 應用平臺上執行得非常順利。以下是我讓它工作的步驟(總共花費時間約為 10 分鐘)
  • 從 Matt 的部落格下載 zip 檔案
  • 執行 'mvn'
  • 將 target/mpapp.war 複製到平臺的 pickup 目錄
  • 啟動平臺:bin/startup.sh。
我在控制檯得到了以下輸出:
com.springsource.platform.deployer.core.DeploymentException: Unable to satisfy constraints of 'myapp' version '0.0.0':
Cannot resolve: myapp  Unsatisfied leaf constraints:
Bundle: myapp_0.0.0 - Import-Package: org.springframework.osgi.web.context.support; version="0.0.0"
Did you mean: 'org.springframework.osgi.context.support'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.ext.servlet; version="0.0.0"
Did you mean: 'javax.servlet'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.core; version="0.0.0"
Did you mean: 'org.hamcrest.core'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.template; version="0.0.0"
Did you mean: 'org.antlr.tool'?
Bundle: myapp_0.0.0 - Import-Package: freemarker.cache; version="0.0.0"
Did you mean: 'org.apache'?
這些是預期的訊息,因為我沒有在平臺中安裝 freemarker 或 osgi.web.context 支援 Bundle。
  • 訪問 http://www.springsource.com/repository。在搜尋框中輸入“freemarker”,找到匹配的條目,點選連結下載。將下載的 Bundle 複製到 repository/bundles/usr
  • 簡化 manifest 檔案,使其指向平臺上的新 Bundle 和庫。原始的 manifest 檔案如下:
Import-Package: javax.servlet,javax.servlet.http,javax.servlet.resources,javax.swing.tree,
javax.naming,org.w3c.dom,org.apache.commons.logging,javax.xml.parsers;resolution:=optional,
org.xml.sax;resolution:=optional,org.xml.sax.helpers;resolution:=optional,
org.springframework.osgi.web.context.support, org.springframework.context.support,
org.springframework.web.context, org.springframework.web.context.support,
org.springframework.web.servlet, org.springframework.web.servlet.mvc,
org.springframework.web.servlet.mvc.support, org.springframework.web.servlet.view,
org.springframework.ui, org.springframework.web.servlet.view.
freemarker, freemarker.cache,freemarker.core,freemarker.template,freemarker.ext.servlet
我將其簡化為:
Import-Package: org.apache.commons.logging
Import-Library: org.springframework.spring;version="[2.5.4,3.0.0)"
Import-Bundle: com.springsource.freemarker;version="2.3.12"
當我們知道您正在部署 Web 應用時,常用的匯入會在部署時自動新增。Import-Library 和 Import-Bundle 讓您可以方便地在單個語句中引用庫和 Bundle。我還刪除了“Bundle-Classpath”條目,因為應用平臺會自動檢測 WEB-INF/lib 中的庫並將其新增到 Bundle 類路徑中。
  • 我編輯了 web.xml 並註釋掉了 context-param 宣告,因為此處無需使用自定義應用上下文型別
  • 再次執行 'mvn',並將 myapp.war 複製到 pickup 目錄中。
  • 應用平臺自動重新部署了應用
  • 在瀏覽器中訪問 https://:8080/myapp/ .... 成功!
我認為這是一個很好的演示,說明了該平臺的價值主張,即為使企業庫在 OSGi 下工作鋪平了道路。

訂閱 Spring 新聞郵件

透過 Spring 新聞郵件保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助力您的進步。

瞭解更多

獲得支援

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

瞭解更多

近期活動

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

檢視全部