SpringSource Application Platform 由 OSGi 捆綁包構建而成,並支援同樣由 OSGi 捆綁包構建的應用程式。平臺支援 OSGi 的標準功能,但也支援一些額外的清單頭部。許多人曾問:“為什麼 SpringSource 要新增專有頭部?”以及“新頭部有什麼含義?”,因此本文解釋了背景動機以及 Import-Library 和 Import-Bundle 的含義。
標準 OSGi 捆綁包支援
平臺基於
OSGi R4.1 標準,或者如果您更喜歡,可以認為是
JSR 291,並使用
Equinox 作為其 OSGi 實現。結果是,您可以使用平臺的工具開發標準的 OSGi 捆綁包,並將這些捆綁包部署到平臺,正如許多使用者自平臺釋出以來一直在做的那樣。
因此,熟悉 OSGi 的開發者可以將平臺用作標準的 OSGi 容器,並受益於平臺的功能,例如:
- 透過管理控制檯或將捆綁包放入平臺的 pickup 目錄來部署捆綁包的能力;
- 診斷功能,如解析失敗診斷、應用程式特定跟蹤和自動死鎖檢測;
- 與 Spring 和 Spring Dynamic Modules 的強大整合,適用於希望使用這些框架的開發人員;以及
- 從儲存庫自動供應依賴項。
然而,平臺還旨在讓接觸 OSGi 很少或沒有經驗的企業應用程式開發人員能夠輕鬆受益於 OSGi,這給平臺帶來了一些額外的要求。
企業應用程式的其他要求
正如 Sam 最近關於平臺部署選項的
部落格 所解釋的,您可以將現有的單體 WAR 檔案部署到平臺上,而無需瞭解 OSGi - 平臺會為您處理一切。但是,要從共享庫、共享服務以及最終的 PAR 檔案範圍中受益,就需要將單體 WAR 檔案分解為 OSGi 捆綁包。這有多難?
好吧,過程中的一些步驟相對容易,特別是如果遵循了良好的軟體工程實踐並且程式碼已被組織成服務、域和基礎設施元件。這些元件可以轉換為捆綁包,它們之間的依賴關係可以使用 META-INF/MANIFEST.MF 中的標準 OSGi Import-Package 和 Export-Package 頭部來表達。
一個更困難的步驟是表達對 Spring 和 Hibernate 等企業框架的依賴。使用標準的 OSGi Import-Package 和 Require-Bundle 頭部來表達這些依賴關係是完全可能的,如果您想建立將在其他 OSGi 容器中執行的 OSGi 捆綁包,那麼您應該這樣做,但這種方法有一些隱藏的成本。
首先,開發人員必須精確地確定構成給定框架的包。僅僅匯入應用程式程式碼使用的包是不夠的,因為許多企業框架在應用程式載入時會在應用程式的位元組碼中注入進一步的依賴關係。開發人員必須透過試錯來發現需要匯入哪些額外的實現包,以確保編織後的應用程式能夠正確執行。
然後是遷移到框架的新版本的工作,其中構成框架的包的精確集已發生更改。編織所需的附加包通常不是由公共契約定義的,因此可能會發生更改。
此外,生成的包匯入未能正確捕獲設計意圖,這使得將來維護或擴充套件應用程式更加困難。
我們真的不想給使用者帶來這些負擔,因此我們建立了一些額外的 SpringSource Application Platform 特定清單頭部,Import-Library 和 Import-Bundle,作為表達對企業框架依賴關係的便捷方式。正如您將在下面看到的,這些頭部只是“語法糖”,它們本身就是標準的 OSGi 包匯入。
Import-Library
基本語法與其他清單頭部類似:
Import-Library: <librarySymbolicName>;version=<versionRange>
其中
<librarySymbolicName> 是庫的“符號名稱”,
<versionRange> 是使用 OSGi 版本範圍表示法可接受的庫版本範圍。庫定義指定了庫的符號名稱和版本,這兩個共同唯一地標識了平臺上的庫。
如果您不熟悉 OSGi 版本範圍表示法,最常用的形式是最小版本範圍,例如 2
,表示“版本 2 或更高版本”,以及“半開”範圍,例如 [2.2.1,2.2.2)
,表示 2.2.1(含)和 2.2.2(不含)之間的任何版本。如果省略 version=<versionRange>,並省略分號分隔符,則預設範圍包含所有版本。
對於每個庫匯入,平臺會選擇具有給定符號名稱和給定版本範圍內的最高版本庫。然後,平臺會將庫匯入替換為一組包匯入,這些包匯入匹配該庫捆綁包匯出的所有包。平臺會檢測到捆綁包匯入兩個或多個匯出公共包的庫的情況,會發出適當的日誌訊息,並阻止匯入捆綁包的安裝。
因此,例如,以下頭部匯入了介於 2.5.4(含)和 2.5.5(不含)之間的某個版本的 Spring Framework 庫。
Import-Library: org.springframework.spring;version="[2.5.4,2.5.5)"
可選庫匯入
您可以使用以下語法指示庫匯入是可選的。請注意,特殊分隔符
:=
表示一個“指令”,它會修改清單頭部的語義,而分隔符
=
表示一個“匹配屬性”,如
version。
Import-Library: <librarySymbolicName>;version=<versionRange>;resolution:=optional
如果未指定 resolution,或者指定為 mandatory,則包含匯入庫頭部的捆綁包將無法安裝,如果不存在具有給定符號名稱且版本在給定範圍內的庫。但是,如果指定了 resolution:=optional,則在沒有合適的庫可用時,將忽略該庫匯入。
因此,例如,以下頭部從 2.5 版本開始匯入某個版本的 Spring Framework 庫,但如果不存在合適的庫,則會被忽略。
Import-Library: org.springframework.spring;version="2.5";resolution:=optional
匯入多個庫
如果您需要匯入多個庫,請在單個
Import-Library 清單頭部中指定一個逗號分隔的庫匯入列表,如下例所示:
Import-Library: org.foo.p;version="[1,2)",org.bar.q;version="[2,3)"
Import-Bundle
Import-Bundle 是一個額外的便利功能,適用於庫僅由一個捆綁包組成且建立庫定義不便的情況。語法非常類似於
Import-Library,只是它引用的是捆綁包的符號名稱和版本,而不是庫的。
正如您所期望的,對於每個匯入的捆綁包,平臺會選擇具有給定符號名稱和給定版本範圍內的最高版本捆綁包。然後,平臺會將捆綁包匯入替換為一組包匯入,這些包匯入匹配該捆綁包匯出的包。
因此,例如,以下頭部匯入了 Hibernate 物件關係對映 捆綁包。
Import-Bundle: com.springsource.org.hibernate;version="[3.2.6,3.2.7)"
為什麼不過載 Require-Bundle?
如果您熟悉 OSGi,您可能會問自己,為什麼我們不過載
Require-Bundle 而引入
Import-Bundle。
嗯,我們希望 Require-Bundle 保留其標準語義,包括將拆分的包組合在一起的能力。但我們希望 Import-Library 和 Import-Bundle 具有與 Import-Package 相同的底層語義,從而避免拆分包的複雜性。
我們還預計,隨著平臺隨時間的推移而發展,我們將需要向 Import-Library 和 Import-Bundle 新增進一步的指令,這些指令不適合新增到 Require-Bundle。
下一步是什麼?
平臺
beta 計劃 正在進行中,我們將聽取所有關於平臺功能(包括新的清單頭部)的反饋。
對於希望利用 Platform 的頭資訊,但又需要生成可在其他 OSGi 容器上執行的 bundle 的使用者,我們計劃推出一個工具,該工具將替換 `Import-Library` 和 `Import-Bundle`……