為 WebSphere Application Server 開發企業 OSGi 應用程式

CloudSpace發表於2010-09-29
Dr. Ian Robinson, 傑出工程師, IBM

簡介: 使用標準 Java™ EE 部署建立模組式、可擴充套件的 Web 應用程式有一定難度,但通常可以通過良好的設計實踐和方法來完成。但是,當您想分離公共模組以便在多個企業應用程式之間共享,或者同時使用多個公共庫版本時,您就會遇到真正的麻煩。OSGi 是多年以來一直在 IBM® WebSphere® Application Server 和 Eclipse 平臺中使用的一種 Java 模組技術。WebSphere Application Server V7 Feature Pack for OSGi Applications and JPA 2.0 允許模組式企業應用程式直接使用 OSGi 技術來極大地簡化它們的開發、組裝和部署。這個特性包還提供了一個基礎設施,其中,模組式設計不僅是一個最佳實踐,而且是惟一的實踐方法。 本文來自於 IBM WebSphere Developer Technical Journal 中文版

介紹

與軟體開發相關的絕大部分成本並不是新應用程式的初始設計、開發和測試成本 — 儘管這些成本可能會比較高 — 而是 後續的維護和完善成本

從一致、版本化、可重用的模組(只能通過定義良好的介面訪問)設計和構建應用程式和應用程式套件降低了複雜性,併為軟體首次釋出之後的維護和完善提供了極大的靈活性。模組式設計(其中模組提供定義良好的服務和介面)允許在多個團隊之間分配大型專案,各個團隊可以專注於各自的任務,不必在公共外部包範圍之外理解其他團隊的程式碼細節,從而降低了每個團隊的工作的複雜程度,減少了完成任務的時間。另外,通過將應用程式的更改影響範圍降到最小 — 假設影響範圍能夠確定,應用程式的維護成本也得以降低。如果一個模組更改隻影響它的內部包,對它的外部包沒有任何影響,那麼可以只對一個單獨的隔離模組進行維護,測試目標也更容易確定。這是顯而易見的,但我們可以從開發工具和執行時基礎設施的積極幫助中獲益,以支援這樣一種模組式設計方式。例如,如果有一種更簡單的方法來部署和維護多個 EAR 使用的公共程式碼,難道這不是很好嗎?

首先,什麼模組才算得上好模組?

  • 該模組應該提供一致的邏輯功能,並且應該足夠的獨立,表示一個實際的 “重用單元”。
  • 該模組應該通過定義良好的外部介面和依賴項與其他模組鬆散耦合
  • 該模組應該將它的內部包與其他模組隔離,以便模組的內部行為更改不會影響其他任何模組。

Java 類粒度太小,不能形成應用程式之間的邏輯重用單元,它們的隔離關注主要侷限於例項資料的封裝。類通常包裝在一個代表一致功能的 JAR 檔案中。作為一個部署單元(和檔案系統中存在的工件),JAR 是一個非常實用的重用單元,但它缺乏作為一個好模組的其他一些特徵。

考慮可見性:如果您在包 bar.foo 的類中有一個對其可用的方法,那麼您需要使用一個公共訪問限定符來宣告該方法。您沒有辦法來表明這個方法是否也應該或不應該對該 JAR 之外的類可用。您可以應用慣例和最佳實踐。可以使用一個包命名慣例將您的介面組織到外部和內部包中。例如,專用於 WebSphere Application Server 的介面包含在 com.ibm.websphere 或 com.ibm.wsspi 的子包中,而專用於應用程式的內部介面主要位於 com.ibm.ws 的子包中。如果在不同的模組上工作的不同團隊遵守模組外部包的定義和用法,那麼這些模組將只通過定義的外部包保持耦合。當然,您的模組中總是有一些 ++ 函式(plus-plus function)不可或缺,但它們不是模組介面的一部分。因此,當另一團隊發現這也會使他們的工作更輕鬆,那麼允許他們繼續使用這些函式又有什麼危害呢?畢竟,你們都在相同的總體專案上工作,且他們將使用的方法都擁有公共 Java 訪問能力,因此不必更改程式碼就可以允許他們使用這些函式 — 如果他們一定要問的話。現在,您無意中打破了 bundle 之間的鬆散耦合。您的 bundle 的內部包的更改 “影響範圍” 現在可能會超出您的 bundle 範圍,這使得確定什麼受到影響,進而確定需要測試什麼更加困難。

那麼,現在有一點很清楚:儘管 JAR 是一個非常實用的重用單元,但它缺乏區分內部包和外部包的能力,因此沒有辦法隔離外部包。比這更糟的是:儘管在另一個環境中提供這個 JAR(您的重用單元)相當容易,但您如何確定這個新環境是否能夠滿足其擁有的所有依賴項的要求呢?如果您在這上面犯錯誤,可能就相當於您的手上拿著一個定時炸彈,即它可能一連數天正常執行,然後需要載入這個新環境沒有的一個類,這時炸彈爆炸 — ClassNotFoundException。這裡的問題是,除了不能提供隔離外,JARs 還不能宣告它們自己的依賴項。

看來,JAR 與良好的可重用模組的要求比較接近,但缺乏一些基本的模組特徵。這就是 OSGi bundle 發揮作用的時候了。

OSGi bundle 一個 JAR,但它在 JAR 清單檔案中擁有附加頭部。在沒有處理這個附加後設資料機制的純 JVM 中,這個 bundle 的表現與普通 JAR 一致。但在包含一個 OSGi 框架的 JVM 中,這個後設資料 被該框架處理,額外的模組特徵得到應用。清單 1 展示了一個示例 MANIFEST.MF。


清單 1. 一個 bundle 清單檔案中的 OSGi 頭部

				
Manifest-Version: 1.0 

Bundle-ManifestVersion: 2 

Bundle-Name: MyService bundle   

Bundle-SymbolicName: com.sample.myservice 

Bundle-Version: 1.0.0 

Import-Package: com.something.i.need;version="[1.0,2.0)" 

Export-Package: com.myservice.api;version=1.0.0

這裡需要注意的一些頭部是:

  • Export-Package 列出將從這個 bundle 匯出的一個或多個包(處於特定版本)。只有匯出包在 bundle 外部可見;這裡沒有列出的包都只在 bundle 內部可見。
  • Import-Package 列出 bundle 需要的一個或多個包(處於特定版本或版本範圍)。

我們現在先不涉及版本控制的細節(將在稍後討論),先來看看這兩個頭部的作用。還記得嗎,前面介紹過,我們需要建立一些開發最佳實踐來定義模組的外部介面並確保沒有任何內部包被任何客戶模組使用。藉助 OSGi,現在可以通過在執行時實施來支援這個最佳實踐,並可以向模組所有者提供一個機制來適當封裝它的內部包。另外,您的包清單檔案中包含一些後設資料,明確指定 bundle 需要的、需要由其他 bundle 提供的所有包。在一個包含許多 bundle 的複雜應用程式中,這將向您提供一個更確定的方法,以確定一個 bundle 更改的影響,並理解對系統其餘部分的可能影響,從而減小軟體開發週期中的風險和成本。

後設資料處理和可見性規則的執行時實施由 OSGi 框架解算器負責。當每個 bundle 啟動時,這個解算器針對此框架中已經安裝的其他 bundle 宣告的匯出協調該 bundle 的每個匯入,併為每個 bundle 計算一個單獨的類路徑。如果某個 bundle 有一個無法解算的依賴項,該 bundle 將不會啟動。前面提到過的滴答作響的定時炸彈(針對一個 JAR 被移動到一個不能滿足其所有依賴項要求的新環境的情況)被通過移除保險絲而拆除。相比處理一個無法啟動的應用程式而言,處理一個正常工作一段時間、然後突然失敗並丟擲一個 ClassNotFoundException 的應用程式要困難得多。

此前我們所討論的內容都不是特定於一個企業執行時的 — 那麼這些內容如何與企業 Java 應用程式或企業應用程式伺服器相關呢?

假設我們有一個企業應用程式伺服器能夠處理 OSGi bundle 後設資料,那麼 OSGi 的第一個明顯的優勢就是包含大量模組的複雜企業應用程式的適當模組化。但 OSGi 的優勢遠不止這些,它還能解決企業環境中普遍的幾個其他問題。我們已經簡單接觸了這些問題中的一個:在部署了數十或數百個 EAR 的許多大型企業部署中,往往存在這樣一種情況:每個 EAR 都是自足的,其程度達到應用程式使用的許多公共庫被打包到需要它們的每個 EAR 中。這些庫副本將塞滿部署這些 EAR 的檔案系統和知識庫,並在應用程式啟動時填滿記憶體。儘管企業應用程式通常可以被部署到各種供應商的企業環境,且管理依賴項已針對獨立於這些 EAR 安裝的共享庫配置,但這些機制因供應商不同而不同,限制了可移植性。另外,共享庫配置通常與部署過程本身分離,需要獨立的、部署後管理配置,這增加了端到端部署過程的複雜性。

OSGi 後設資料和 bundle 知識庫向您提供了一個機會,允許您只在應用程式存檔中包含特定於應用程式的模組,從而極大地簡化共享公共庫的企業應用程式套件的部署。在理解 OSGi 後設資料之後,企業部署過程變得更加強大,能夠針對部署環境中配置的 bundle 知識庫的內容解算 bundle 依賴項。所有公共庫都可以在一箇中央 bundle 知識庫中管理,該知識庫然後成為企業(單元)配置的一部分。

OSGi 還向您提供了一個機會,允許您在企業環境中更好地執行版本控制工作。當今企業應用程式通常包含對公共庫有相似依賴性的第三方框架和庫。如果不同框架需要不同版本的公共庫,那麼這將是個令人頭痛的問題。當您遇到下面的情況時,這個問題將變得尤其嚴重:以前,您的應用程式一切正常,但現在您需要更新一個供應商框架,結果卻發現辦不到,原因是該框架在應用程式中的另一個框架使用的一個庫的不相容的新版本上有一個依賴項。

OSGi 版本控制後設資料和類載入能夠消除這個問題。在上面的清單 1 中,Import-Package 頭部表明包 com.something.i.need 上的一個依賴項,版本範圍 為 “[1.0,2.0)”。這表明這個依賴項的需求範圍為 1.0 ≤ version < 2.0 的任何包版本。因此,version 1.0 或 1.5.0 或 1.9 都能滿足這個依賴項的需求,但 version 2.0 不能。OSGi 的版本控制機制支援包提供者在版本的主要部分中使用一個標明,一個不相容更新的更改來表明一個包的新版本是否向前相容前面的版本。包使用者可以指出他們能夠使用的版本或版本範圍。(請參閱 這份 PDF 白皮書 瞭解關於 OSGi 版本控制的更多資訊。)重要的是,如果一個應用程式中的兩個 bundle 依賴同一個包的不同版本,那麼這些依賴項的需求可以同時得到滿足,因為 OSGi 解算器可以為這兩個 bundle 計算不同的類路徑。

OSGi 平臺規範,以及參考實現和依從性測試,由 OSGi Alliance 生成,10 多年來一直被廣泛使用。2010 年 3 月,OSGi V4.2 Enterprise Specification 出版物包含了企業環境。該出版物定義了企業 Java 技術的一些 OSGi 語義,比如事務、永續性和 Web 元件。這個重要的規範定義了一些標準機制來將結合 Java EE 和 OSGi 世界,包含了 bundle 後設資料來宣告該 bundle 包含一個 web.xmm 檔案的 Web bundle、包含一個 persistence.xml 檔案的永續性 bundle、還是包含一個 blueprint.xml 檔案的 Blueprint bundle。Web 和永續性 bundle 只是包含額外 OSGi 清單檔案頭部的常見 Java EE bundle;而 Blueprint bundle 更像 Spring 模組,但包含一個標準化的 bean 定義 XML。

作為一種技術,OSGi 在獨立應用程式和客戶端應用程式技術中已經流行了多年,並在許多企業應用程式伺服器(比如 WebSphere Application Server)的實現中內部使用。由於缺乏企業應用程式的 OSGi 標準,以及缺乏廣泛可用的專用工具和企業執行時支援,在這些應用程式伺服器平臺上執行的企業應用程式對 OSGi 的直接利用最近受到抑制。隨著 OSGi Enterprise Specification 的釋出,以及可以選擇在越來越多的企業應用程式伺服器上將應用程式部署為 OSGi bundle,這種情況得到了改觀。

本文餘下部分將討論開發和部署 WebSphere Application Server V7 Feature Pack for OSGi Applications and JPA 2.0 中引入的企業 OSGi 應用程式的執行時和工具化支援:

WebSphere Application Server V7 Feature Pack for OSGi Applications and JPA 2.0 在 WebSphere Application Server 中引入了 OSGi 應用程式支援。與其他 WebSphere Application Server 特性包一樣,這是一個 免費提供的下載,可以以附加方式在一個現有 WebSphere Application Server V7.0.0.9 或更高版本上安裝和解除安裝。這個特性包實際上包含兩個可安裝特性:OSGi 應用程式特性JPA 2.0 特性。這兩個特性可以單獨安裝,也可以同時安裝;同時使用時,它們提供一個簡化的、基於 POJO 的元件模型、高效能永續性框架、以及簡化 Web 應用程式開發和單元測試的模組化開發系統。本文只關注 OSGi 應用程式特性。

WebSphere Application Server OSGi 應用程式特性支援以模組化方式開發和部署企業應用程式,將可配置的 OSGi bundle 知識庫引入 WebSphere Application Server 管理流程。這允許將公共 bundle 從單獨的企業應用程式存檔中分離出來,並在一個 bundle 知識庫中集中管理。一個 bundle 知識庫可以管理多個 bundle 版本,與單獨的企業應用程式關聯的適當版本可以在那些應用程式的後設資料中指定。

我們來看看成為 WebSphere Application Server 中的一個 OSGi 應用程式意味著什麼?

在最基本的層面上,一個 OSGi 應用程式可能是部署在一個 Java EE 存檔(EAR)中的相同的模組集合,但帶有支援將這些模組載入為 OSGi bundle 的額外的 OSGi 後設資料。儘管使用 Java EE 類載入器按照一個標準 Java EE 應用程式執行這個應用程式和使用 OSGi 類載入器按照一個 OSGi 應用程式執行該應用程式產生的最終結果沒有什麼區別,但由於以下幾個原因,您可能會選擇開發和部署一個 OSGi 應用程式:

  • 應用程式可以部署在只包含應用程式特有內容(理想情況)的存檔中,並使用後設資料引用任何共享庫(bundle)。應用程式存檔變得更小,且只有單個公共庫副本被載入到記憶體中。
  • 使用標準 OSGi 機制,可以同時在同一個應用程式中載入多個類版本。
  • 已部署的應用程式可以以模組化方式、在 bundle 層面上更新。
  • 在開發時,IBM Rational® Application Developer 中的 OSGi 專案實施 OSGi 可見性規則,以便這些專案只能訪問來自其他一些專案的包,那些專案將這些包顯式宣告為專案外部包的一部分,從而為開發最佳實踐提供環境支援。
  • 應用程式可以設計為通過使用 OSGi 服務提高可擴充套件能力並實現動態更新。
  • 在執行時,應用程式僅當它的所有依賴項能夠被解算時才能成功啟動,從而減少應用程式在處理一個工作負載時出現 ClassNotFoundExceptions 的機率。
  • 應用程式可以使用與伺服器執行時不同的、自己的公共實用程式類版本,而不必配置 PARENT_LAST 模式這樣的 Java EE 類載入器策略。

當您的應用程式複雜性增加,或者已部署的應用程式套件的規模增大時,管理對應用程式的模組和它們使用的實用工具庫的更新就會變得更困難。這時,使用 OSGi 的好處就會變得甚至更加明顯。

有幾種方法可以開始在 WebSphere Application Server 上部署您的首個 OSGi 應用程式。最常見的方法也許是從您已經熟悉的一個現有 Java EE Web 應用程式開始,或者從 OSGi 應用程式特性中包含的樣例應用程式開始。無論採用哪種方式,都需要將 OSGi 應用程式打包為一種可以部署的格式。

與其他任何應用程式一樣,OSGi 通過 wsadmin 或 WebSphere Application Server 管理控制檯部署,但被打包為一種稱為企業 bundle 存檔(enterprise bundle archive,EBA)的新型存檔。這種存檔與 EAR 相似,但它的模組作為 bundle 部署到理想的目標伺服器。一個 EBA 代表包含一個或多個應用程式模組的單個獨立 OSGi 應用程式,是一個企業 OSGi 應用程式的部署單元。與 EAR 檔案類似,一個 EBA 可以包含組成應用程式的所有組成模組或 bundle,相反,也可以只包含從一個已配置的 bundle 知識庫定位那些 bundle 需要的後設資料。這種後設資料採用一個 EBA 級的 APPLICATION.MF 檔案形式,該檔案描述應用程式的內容以及應用程式是否公開任何外部服務和引用。就像 bundle 清單檔案描述 bundle 的模組特徵一樣,應用程式清單檔案描述應用程式的模組特徵,以及該應用程式可部署的內容。

清單 2 顯示了一個簡單 OSGi 應用程式的完整應用程式清單檔案。Application-Content 頭目描述組成應用程式的主要 bundle,以及應用程式部署時將部署的 bundle。部署應用程式需要一個 “內容列表” 的原因是並非所有這個內容都需要包含在 EBA 中的應用程式清單檔案中;這些 bundle 當然可以被打包到存檔中,但它們中的全部或部分同樣可以通過 WebSphere Application Server 部署流程從一個已配置的 bundle 知識庫提供。例如,如果 com.example.common.audit bundle 為一個 IT 組織管理的所有應用程式提供公共審計服務,該 bundle 應該安裝到一個公共 bundle 知識庫中而不是部署為每個應用程式 EBA 的一部分。


清單 2. 一個 OSGi 應用程式的簡單 APPLICATION.MF

				
Application-Name: MyApp

Application-SymbolicName: com.example.app

Application-Version: 1.0

Application-Content: com.example.app.web;version=1.0.0,

com.example.app.persistence;version=1.0.0,

com.example.common.audit; version=1.0.0

通過 OSGi 應用程式特性,WebSphere Application Server 提供一個內建 OSGi bundle 知識庫,該知識庫的內容可以通過 WebSphere Application Server 管理控制檯管理,如圖 1 所示。WebSphere Application Server 還允許選擇使用一些外部 OSGi bundle 知識庫,這些知識庫通過一個已配置的知識庫 URL 訪問。


圖 1. 管理控制檯中的 OSGi bundle 知識庫
圖 1. 管理控制檯中的 OSGi bundle 知識庫

在 OSGi 應用程式部署過程中,WebSphere Application Server 管理控制檯為應用程式計算所有包和 OSGi 服務級別依賴項,以便該應用程式能夠由 EBA 和已配置的 bundle 知識庫一起完整提供。應用程式清單檔案本身可以由開發人員建立,也可以由 Rational Application Developer 這樣的工具生成。重要的是要理解,應用程式清單檔案只需在 Application-Content 中列示主要的應用程式 bundle,而不必列示這些主 bundle 依賴的所有包提供的和服務提供的 bundle。WebSphere Application Server 部署流程解算主 bundle 的所有依賴項,以計算一個短暫關閉的應用程式內容列表,並在解算過程檢測到依賴項缺失時阻止應用程式部署。還需要理解的一個重點是,配置按例外管理(by-exception),因此,如果 Application-Content 全部包含在 EBA 中,則應用程式清單檔案完全不必要。構成 Application-Content 一部分的每個模組,以及其全部已計算依賴項,部署為一個 OSGi bundle。如果一個不帶 OSGi 後設資料的 Web 模組包含在 Application-Content 中,那麼 WebSphere Application Server 部署流程將在部署過程中自動將這個模組轉換為一個 Web 應用程式 bundle(WAB 模組)。按例外配置(configuration-by-exception)以及 WAR 檔案的自動檢測和轉換提供一種最快捷的方法來開始使用 OSGi 應用程式 — 可以將一個只包含 Web 模組的 Java EE EAR 部署為一個 OSGi 應用程式,只需將該存檔的副檔名 .ear 更改為 .eba。

OSGi (通過 OSGi 服務)引入的另一個特性是一個標準可擴充套件性模型。您可以設計您的應用程式以利用 OSGi 豐富的基於服務的動態模型,從而使用來自 OSGi 服務登錄檔的服務。這樣,OSGi 服務就成為可以設計到您的應用程式中的擴充套件點,應用程式將來可以通過單獨的 bundle 引入的服務提供商實現來進行擴充套件,且不必為原始應用程式程式碼付費。OSGi 定義一些 Java API 來註冊和發現 OSGi 服務,但 OSGi 服務的一個宣告性方法更加簡單。這就是企業 OSGi V4.2 Blueprint 容器發揮作用的地方:Blueprint 容器管理 POJO bean 元件的生命週期和依賴項注入,並通過一個應用程式級別 XML bean 定義檔案配置,這個檔案是 Spring bean 定義 XML 的基於標準的演變。通過標準化 OSGi Alliance 中的 bean 定義 XML 架構和 bena 生命週期管理語義,就有可能將依賴項注入容器從應用程式(其中通常打包了 Spring 框架庫)分離出來並重構到中介軟體中。在安裝 OSGi 應用程式特性時,來自 Apache Aries 專案的企業 OSGi v4.2 Blueprint 容器實現被整合並擴充套件為 WebSphere Application Server 執行時的一部分。

Blueprint 為 OSGi 應用程式提供了一個細粒度的 bean 組裝模型,以及一種簡單的宣告性方法來發布由 POJO bean 元件提供的服務。例如,清單 3 中顯示的 bean 定義程式碼段定義了一個 bloggingServiceComponent bean(通過 BloggingServiceImpl 類實現),一個 BloggingService 服務在 OSGi 服務登錄檔中註冊了這個 bean。


清單 3. Blueprint bean 定義

				

  





  ...

在這個示例中,這個容器在被例項化時將 3 個屬性(可能是對 bean 定義檔案 blueprint.xml 中其他位置定義的 OSGi 服務或 beans 的引用)注入到 bloggingServiceComponent bean 中。Blueprint 配置的 beans 向 OSGi 應用程式提供了一種方便的方法來將它們的業務邏輯封裝到一些 POJO 元件中,這些 POJO 元件已經通過 Blueprint 容器在其中注入了它們的依賴項和配置。由於這些 POJO bean 元件在應用程式伺服器上沒有 Java 依賴項,因此在一個純 Java SE 或 Eclipse 環境中對業務邏輯進行單元測試非常簡單。

我們現在來看看 OSGi 應用程式特性自帶的一個樣例,以瞭解這樣的應用程式通常是如何開發和部署的。這個樣例是一個簡單的部落格釋出應用程式,演示如何在一個 OSGi 應用程式中聯合使用 Web、Blueprint 和永續性技術。(如果您想深入研究其程式碼,請檢視 OSGi Applicantion 特性包自帶的這個部落格應用程式的原始碼。)


圖 2. 部落格樣例應用程式
圖 2. 部落格樣例應用程式

這個部落格樣例展示了企業應用程式的典型架構。該架構包含 4 個鬆耦合 bundle:一個 Web 層、一個業務邏輯層、一個持久化層、以及一個 API bundle。

首先,注意如何將這些 API 拉到它們各自的 bundle 中。這是保持耦合鬆散的一個 OSGi 最佳實踐。如果必要,一個實現可以在部署時或甚至在執行時輕鬆交換為另一個實現。

bundle 之間的耦合利用一個基本 OSGi 構造 — 服務(在圖 2 中表示為三角形),服務在 bundle 之間維護理想的鬆散耦合並允許以對應用程式其餘部分的最小影響更輕鬆地替換 bundle 實現。如 OSGi 服務和 Blueprint 元件模型 所述,OSGi 應用程式不必直接與 OSGi 服務登錄檔互動,相反,可以通過簡單 POJO beans 的宣告性 Blueprint 配置這樣做。blog-biz 和 blog-persistence bundle 都是用 Blueprint 配置的 beans 來封裝業務邏輯,並通過管理它們的生命週期的 Blueprint 容器將它們的依賴項和配置注入自身。Blueprint 容器將 blog-biz bundle 中的 beans 連線到一起,並將 blog-biz bundle 中的元件連線到 blog-persistence bundle 提供的 Blog persistence 服務。

應用程式的前端是一個使用我們熟悉的 Java EE servelet 元件的 Web 模組。為演示結合 Java EE 程式設計風格和基於服務的 OSGi 風格是多麼簡單,樣例 blog-web bundle 遵循一個純 Java EE 程式設計模型並使用 JNDI 來訪問 Blueprint 釋出的 OSGi 服務。企業 OSGi 規範為 JNDI 客戶機定義了一個標準機制來獲取 OSGi 服務的引用,在兩種程式設計風格之間架起了一個天然的橋樑。

blog-persistence-jpa bundle 將 JPA 用作永續性框架,條目通過該框架持久儲存到一個資料庫並從該資料庫檢索。它利用 Blueprint 容器的功能來管理永續性上下文和全域性事務,以確保業務邏輯的開發和單元測試儘可能保持簡單。

最後,這些部落格 JAR 被打包到一個 EBA 中並部署到 WebSphere Application Server。

我們下面仔細看看這個應用程式的每個元素。

API bundle

API bundle 是最簡單的元件,這也許不會令人感到奇怪。它是一個簡單的 OSGi bundle,不利用任何企業特性。如前所述,正是 JAR 清單檔案中的 OSGi 後設資料向 JAR 賦予 “bundle 特徵”。在這個部落格 API 示例中,這個 bundle 宣告匯出 com.ibm.ws.eba.example.blog.api、com.ibm.ws.eba.example.blog.comment.persistence.api 和 com.ibm.ws.eba.example.blog.persistence.api 三個包,版本號為 1.0.0。


清單 4. 部落格樣例 API bundle 清單檔案

				
Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: blog

Bundle-SymbolicName: com.ibm.ws.eba.example.blog.api

Bundle-Version: 1.0.0

Export-Package: 

com.ibm.ws.eba.example.blog.api;version=1.0.0,

com.ibm.ws.eba.example.blog.comment.persistence.api;version=1.0.0,

com.ibm.ws.eba.example.blog.persistence.api;version=1.0.0

Web 應用程式 bundle

在很多方面,Web bundle 都與標準的 Java EE Web 存檔相似,它在一個 web.xml 檔案中宣告它的 servlet 對映,將其程式碼打包到 WEB-INF/類中。但是,也有一些區別。對於一個 OSGi bundle,您將與其清單檔案宣告一些匯入 — 本例中為 API bundle 匯出的部落格 API。Web-ContextPath 在清單檔案,而不是 EAR 的 application.xml 檔案中宣告。這個區別的實際原因是 OSGi 應用程式不是一個 EAR,因此沒有 application.xml 檔案。但是,還有一個更重要的動機。將 Web 模組的所有配置資訊都儲存在 Web bundle 本身中使 Web 存檔的模組性和獨立性更高,從而保持了 OSGi 的精髓。


清單 5. 部落格樣例 Web bundle 清單檔案

				
Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-ClassPath: WEB-INF/classes

Bundle-Name: blog.web

Bundle-SymbolicName: com.ibm.ws.eba.example.blog.web

Web-ContextPath: blog

Bundle-Version: 1.0.0

Import-Package: 

com.ibm.ws.eba.example.blog.api;version="[1.0.0,1.1.0)",

com.ibm.json.java;version="[1.0.0,2.0.0)"

WebSphere Application Server 中的 OSGi 框架將這個存檔識別為一個 Web bundle 並將其傳遞給一個 Web 容器,以管理 servlets 的生命週期。Java EE Web 容器和 OSGi 容器之間的整合通過聯合的 JNDI 查詢實現,這種查詢是企業 OSGi 規範的一個特性。所有 OSGi 服務都自動在 JNDI 中註冊,並可以以訪問 Java EE 元件的熟悉方式訪問。例如,這個部落格 servlet 訪問 BloggingService 的一個實現,如清單 6 所示。


清單 6. 從 Web 元件訪問 OSGi 服務

				
InitialContext ic = new InitialContext();

return (BloggingService) ic.lookup("osgi:service/"

+ BloggingService.class.getName());

同樣,也可以使用一個 @Resource 註釋來注入這個引用,作為使用這個 JNDI Context API 的替代方法。

Blueprint bundle

業務邏輯被實現為一個 POJO 集合,並通過一個宣告性 blueprint.xml 配置檔案將 bean 定義和引用與 OSGi 服務關聯起來。Blueprint 容器負責與 OSGi 服務登錄檔互動,以管理與服務的互動和服務的生命週期。清單 3 中展示的 blueprint.xml 來自這個部落格樣例業務 bundle,展示了宣告一個 bean,注入其依賴項(可能是服務和其他 beans 的引用)並將這個 bean 釋出為一個服務的一個典型模式。

永續性 bundle

永續性 bundle 使用企業 OSGi 的另一個標準特性 — JPA 整合 — 來利用託管永續性。JPA 永續性單元同樣通過一個 persistence.xml 檔案來配置。永續性 bundle 的 bundle 清單檔案需要一個 Meta-Persistence 頭部來表明它是一個永續性 bundle,如清單 7 所示。


清單 7. 部落格樣例永續性清單檔案

				
Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: blog.persistence

Bundle-SymbolicName: com.ibm.ws.eba.example.blog.persistence

Bundle-Version: 1.0.0

Meta-Persistence: 

Import-Package:

com.ibm.ws.eba.example.blog.persistence.api;version="[1.0.0,1.1.0)",

javax.persistence;version=1.0.0

永續性 bundle 實際上不僅僅獲取一個託管 JPA,而是一個容器 託管 JPA,因為它是一個 Blueprint bundle(以及一個永續性 bundle);Blueprint 容器全面管理 JPA PersistenceContext 並將其注入為 blogExample 永續性單元註釋的託管 bean(BlogPersistenceServiceImpl)中。


清單 8. 基於註釋的 JPA EntityManager 注入

				
private EntityManager em;

@PersistenceContext(unitName = "blogExample")

public void setEntityManager(EntityManager e) {

em = e;

}

作為註釋這個 bean Java 程式碼的一種替代方法,容器託管的 PersistenceContext 能夠通過在 Blueprint bean 定義中使用 元素來宣告,如清單 9 所示。


清單 9. Blueprint 容器託管的 Transaction 和 Persistence 配置

				




清單 9 還展示了一些 Blueprint 容器託管的事務。在這個示例中,persistenceManager bean 的所有方法都在 Blueprint 容器建立(或連線)的一個全域性事務下執行。WebSphere Blueprint 容器支援的容器託管的事務值集合與 EJB 容器支援的集合相同。(參見 事務和 OSGi 應用程式 瞭解更多資訊。)

應用程式組裝

這個樣例部落格應用程式的最後一個部分是 EBA。如 前文 所述,EBA 是可部署的單元,包含一個描述應用程式內容的應用程式清單檔案。對於這個部落格樣例,應用程式清單檔案看起來如清單 10 所示。


清單 10. 部落格樣例 APPLICATION MANIFEST

				
Application-Name: Blog

Application-SymbolicName: com.ibm.ws.eba.example.blog.app

Application-Version: 1.0

Application-Content:

com.ibm.ws.eba.example.blog.api;version=1.0.0,

com.ibm.ws.eba.example.blog.persistence;version="[1.0.0, 2.0.0)",

com.ibm.ws.eba.example.blog.web;version=1.0.0,

com.ibm.ws.eba.example.blog;version=1.0.0

Use-Bundle: com.ibm.json.java;version=1.0.0

這個應用程式級後設資料已在 前文 中介紹過。這個部落格樣例清單檔案中有兩點需要注意:

  • 為應用程式部署的 API、部落格和 Web bundle 的版本必須是 1.0.0 版或更高版本,但永續性bundle的版本範圍必須為 1.0.0 到 2.0.0(不包括)。這意味著,儘管所有 bundle 在應用程式初始部署時都可以處於 1.0.0 版,但應用程式已被組裝為支援這些 bundle 的未來更新。如果在應用程式部署之後的某個時間,永續性 bundle 的一個 1.1.0 版變得可用,那麼 WebSphere Application Server 管理員可以(通過 wsadmin 或管理控制檯)更新應用程式中的那個 bundle。這個部落格樣例提供部落格永續性 bundle 的一個附加 1.1.0 版來演示這個管理更新功能。
  • Use-Bundle 頭部獨立於 Application-Content 列示 com.ibm.json.java bundle。這表明這個 bundle 是可以與其他應用程式共享的。Application-Content 中列出的所有 bundle 將在一個 OSGi 框架例項中執行,這個框架將這些 bundle 與同一個應用程式伺服器中的其他 OSGi 應用程式隔離。這樣,一個 OSGi 應用程式就不會對另一個 OSGi 應用程式產生不必要的副作用,這只是因為該 OSGi 應用程式被部署到同一個目標伺服器。由於 OSGi 應用程式支援的目標之一是以一種與部署過程整合的方式簡化應用程式之間的模組共享,Use-Bundle 頭部提供了一種機制來識別應該被共享的模組。除了顯示 Use-Bundle 內容外,其包或服務在應用程式部署時被隱式解算的任何 bundle 也視為正在提供共享內容。當應用程式在目標伺服器上啟動時,被識別為正在被共享的任何 bundle 都將被載入到一個伺服器範圍的父 OSGi 框架中,該框架的內容對每個隔離的應用程式框架都可見。

這個部落格樣例被打包為演示 WebSphere Application Server bundle 知識庫的使用:一個必要的 bundle com.ibm.json.java 獨立於 blog.eba 存檔提供。這個共享 bundle 必須在 blog.eba 部署之前安裝到 WebSphere Application Server bundle 知識庫中。部署過程根據已部署的 EBA 存檔、已配置的 bundle 知識庫和 WebSphere Application Server 提供的 API/SPI 包(比如 Java EE 包和 com.ibm.websphere 包)的內容計算這個包以及所有應用程式 bundle 的依賴項。如果所有依賴項都被解算,則應用程式將被成功部署到已配置的目標伺服器。在 WebSphere Application Server 管理控制檯中,已安裝的 OSGi 應用程式作為 Java EE 和 SCA 應用程式出現在相同的 Business-level applications (BLA) 集合檢視中。(請參見 部署 OSGi 應用程式的管理任務 瞭解更多細節。)

WebSphere Application Server V7 Feature Pack for SCA v1.0.1.5 或更高版本被安裝後,OSGi 應用程式特性可以與 WebSphere Application Server 的 Service Component Architecture (SCA) 支援聯合使用。SCA 提供一個組裝模型來將可能異構的元件合成為一些粗粒度的複合(composite),這些複合定義一些外部服務和引用,可以為它們配置各種不同的 bundle。關於使用顯式宣告的外部包將一些元件組裝為一個一致的模組的概念方面,SCA 和 OSGi 共享一些公共概念。聯合使用這些技術非常自然,儘管它們確實處理服務組裝的不同和獨特方面。

OSGi 應用程式本身可以從一個 OSGi bundle 集合組裝,每個 OSGi bundle(比如這個部落格樣例應用程式的 Web、業務和永續性 bundle)都執行應用程式中的一個一致功能。

  • 在 bundle 內部,細粒度元件使用一個 Blueprint bean 定義實現為 POJO beans 並連線在一起;一個 bundle 的內部包對其他 bundle 不可見。
  • 在 OSGi 應用程式內部,bundle通過 OSGi 服務或外部包依賴項連線在一起;一個 OSGi 應用程式的內部包對其他應用程式不可見。

上面是兩種不同級別的模組性。SCA 提供另一個級別:

  • 在一個 SCA 複合內部,SCA 元件通過 SCA 服務連線在一起;一個 SCA 複合的內部包對其他複合不可見。

一個 OSGi 應用程式可以組裝為一個粗粒度的 SCA 複合中的一個 SCA 元件,並可以有選擇地公開它實現的 OSGi 服務,使用 SCA 來為這些服務提供遠端繫結。OSGi 應用程式提供的 SCA 元件實現的 SCA 元件型別為 implementation.osgiapp。它可以將其 Blueprint 配置的任何 OSGi 服務遠端公開為 SCA 服務,併為這些服務配置遠端繫結。

例如,假設您想將這個部落格樣例 OSGi 應用程式作為一個 SCA 元件,以及其他一些實現型別不同的元件(比如 EJB 元件)組合為一個 SCA 複合,然後將清單 3 中的程式碼段中定義的 bloggingServiceComponent 公開為一個帶有預設 SCA bundle 的外部服務。您首先需要更新包含這個程式碼段的 Blueprint 服務定義,以表明這個服務是遠端可用的。這需要在這個服務定義中新增一個標準 OSGi 屬性 service.exported.interfaces,如清單 11 所示。


清單 11. 宣告一個服務遠端可用

				

  
    ...






  ...

清單 10 中展示的應用程式清單檔案需要表明這個服務應該在 OSGi 應用程式外部可見。為此,嚮應用程式清單檔案新增 Application-ExportService 頭部,如清單 12 所示。


清單 12. 從 OSGi 應用程式匯出服務

				
Application-Name: Blog

Application-SymbolicName: com.ibm.ws.eba.example.blog.app

Application-Version: 1.0

...

Application-ExportService: com.ibm.ws.eba.example.blog.api.BloggingService

現在您可以配置一個其實現為 OSGi 應用程式並提供一個 SCA 服務的 SCA 元件,如清單 13 所示。


清單 13. 配置一個 SCA 元件

				








在這個示例中,顯示了一個預設 SCA bundle,但也可以指定其他 bundle(比如 Web 服務的 binding.ws 或 JMS 的 binding.jms),具體取決於需要如何公開服務。

與匯出遠端服務的方式相似,implementation.osgiapp SCA 元件可以匯入遠端服務引用。關於聯合使用 OSGi 和 SCA 的場景和模式的詳細討論超出了本文的範圍。(請參見 在 SCA 複合中組裝和部署 OSGi 元件的相關文件 瞭解更多資訊。)

用於構建企業 OSGi 應用程式的大部分開發行為和開發工具與 Java EE 工具類似,但有一些新的考慮。這些考慮主要圍繞編譯時類路徑,以及 OSGi bundle、應用程式清單檔案及可選的 Blueprint bean 定義檔案的編寫。Rational Application Developer 附件支援 開發 OSGi 應用程式工具,為 OSGi bundle 專案和應用程式專案引入了新的專案型別,並自動生成清單檔案和基於表單的編輯器來修改它們。OSGi 模組化語義在專案構建路徑中受到支援,以便只有在專案的 bundle 清單檔案中顯式匯入和匯出的包在專案之間共享。Rational Application Developer 的基於面的配置支援將 OSGi 專案配置為 OSGi Web 專案或 OSGi JPA 專案,並整合一些工具來編寫 web.xml、persistence.xml 和 blueprint.xml。Rational Application Developer 的新 bundle Explorer 可用於視覺化 OSGi 應用程式中的 bundle 之間的關係,如圖 3 所示。OSGi 應用程式專案可以匯出到 .eba 存檔或從中匯入,並可以從 Rational Application Developer 工作空間執行,該工作空間可以位於 Rational Application Developer 可選安裝的 WebSphere Application Sever V7 中,也可以位於包含 OSGi 應用程式特性的遠端 WebSphere Application Server V7 環境中。


圖 3. Rational Application Developer bundle Explorer
圖 3. Rational Application Developer bundle Explorer

除了整合的 Rational Application Developer 工具外,還有幾個開源工具可以幫助生成 OSGi bundle 清單檔案。另外,Apache Aries 社群開發的 EBA Maven Plugin 也可以從作為一個構建的一部分的 Maven pom 配置生成一個 OSGi 應用程式清單檔案。

 

操作細節

目前為止我們已經討論瞭如何開發、組裝和部署 OSGi 應用程式。本小節簡單介紹一個部署的結果,以及後續可以採取的一些管理操作。

WebSphere Application Server OSGi 應用程式特性包提供的一個有用的實用程式是安裝在 install_dir/feature_packs/aries/bin/ 目錄中的 osgiApplicationConsole 指令碼。這是一個 wsadmin 客戶機應用程式,旨在為指定應用程式伺服器提供一個遠端 OSGi 控制檯。命令列引數如清單 14 所示。


清單 14. 使用 OSGi 應用程式控制臺實用程式

				
-h The host name of the target machine.

-o The port number of the SOAP port of the target server

-u The user ID, if the wsadmin connection is secured. 

-p The password, if the wsadmin connection is secured.

example: 

install_dir/feature_packs/aries/bin/osgiApplicationConsole -h server1.acme.com -o 8880

在命令提示中,可以鍵入 help() 顯示一個互動命令列表。如果您在部署和啟動這個部落格樣例應用程式之後執行這個命令並在命令提示中鍵入 list(),您將看到目標伺服器上的兩個 OSGi 框架的條目。一個是 OSGi 框架,這個部落格樣例應用程式就安裝在該框架中;另一個是伺服器範圍的共享框架。要了解每個框架的 bundle、服務和包的相關細節,需要首先連線到想要的框架:從命令提示符處鍵入 connect(1) 以連線到應用程式框架。要列示這個框架中安裝的所有 bundle,並檢視它們的 bundle 狀態,鍵入 ss()。您應該能夠看到類似清單 15 的結果。


清單 15. 互動式 OSGi 應用程式控制臺

				
wsadmin>ss()

ID State bundle  

0 ACTIVE org.eclipse.osgi_3.5.2.R35x_v20100126

1 ACTIVE com.ibm.ws.eba.example.blog.app_1.0.0

2 ACTIVE com.ibm.ws.eba.example.blog.persistence_1.0.0

3 ACTIVE com.ibm.ws.eba.example.blog.web_1.0.0

4 ACTIVE com.ibm.ws.eba.example.blog.api_1.0.0

5 ACTIVE com.ibm.ws.eba.example.blog_1.0.0

WebSphere Application Server Information Center 記錄了一些互動式命令和過濾器,用於獲取關於正在執行的應用程式的資訊。這個控制檯可以幫助您很輕鬆地以可視方式檢視如何為分離的 OSGi 應用程式維護隔離,通過隔離,一個應用程式的內部 bundle 和包將對其他應用程式不可見。要隔離一個應用程式和另一個應用程式,您不必將它們部署在不同的伺服器上。需要在應用程式之間共享的 bundle(例如,此前介紹的連結到 Application Assembly 的 Use-Bundle 內容)被安裝到共享框架中。

最後,我們看看已部署應用程式中的 bundle 的管理更新。

應用程式安裝後,可以導航到管理控制檯的 Assets 檢視,檢視每個 bundle 的已安裝版本。如果任何已配置 bundle 知識庫中有一個或多個 bundle 的更新版本可用,且那些版本處於為 OSGi 應用程式清單檔案中的 bundle 定義的版本範圍中,那麼您有機會以管理方式將那些 bundle 中的全部或一部分更新到想要的版本。為了便於演示,這個部落格樣例提供了它的永續性 bundle 的一個額外的 1.1.0 版。如果您在這個部落格樣例部署之後將這個部落格永續性 bundle 的 1.1.0 版新增到 WebSphere Application Server 內部 bundle 知識庫,則可以通過皮膚中的 Application Assets 檢視進行導航,如圖 4 所示。


圖 4. bundle 的管理更新
圖 4. bundle 的管理更新

您現在可以選擇這個永續性 bundle 的 1.1.0 版並選擇 Preview 按鈕來重新解算應用程式,並檢查任何不一致。如果預覽沒有生成錯誤,那麼您可以選擇 Commit 按鈕來更新應用程式並儲存配置。

模組式應用程式設計方法的好處包括降低複雜性、減少交付時間和提高服務能力。儘管開發人員非常理解這些好處,經常採取一些最佳實踐來鼓勵模組式設計,但 Java EE 基礎設施自身實施或鼓勵模式式設計的能力有限。

企業 OSGi 將 OSGi 的模組性原理和基礎設施與用於企業應用程式及其執行的伺服器環境的一個熟悉的 Java EE 程式設計模型結合起來。

WebSphere Application Server V7 Feature Pack for OSGi Applications and JPA 2.0 的 OSGi 應用程式特性為將 OSGi 應用程式部署到 WebSphere Application Server 提供了綜合的執行時和整合管理支援。通過使應用程式相互隔離,同時支援共享應用程式組裝後設資料標示的特定 bundle,應用程式完整性得到維護。應用程式部署流程被擴大為支援從特定於應用程式的存檔和共享的 OSGi bundle 知識庫提供應用程式內容,從而減小了應用程式存檔大小以及磁碟和記憶體佔用。類似於 Spring 的宣告式組裝和依賴項注入,以及簡化應用程式外部的單元測試的好處,通過由 OSGi 標準管理並整合到伺服器執行時的 Blueprint 容器提供。OSGi 應用程式到異構複合的組裝和 OSGi 服務的遠端繫結通過 OSGi 應用程式的一個新 SCA 元件實現提供。

OSGi 開發人員的工具化通過 Rational Application Developer 提供,包括 OSGi 後設資料的生成器和編輯器、開發環境中的 OSGi 模組化約束的實施、企業 bundle 存檔的匯入/匯出、以及在伺服器中執行和除錯 OSGi 應用程式的工作空間整合功能。

現在就試試吧!

原文連結:http://www.ibm.com/developerworks/cn/websphere/techjournal/1007_robinson/1007_robinson.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14789789/viewspace-675107/,如需轉載,請註明出處,否則將追究法律責任。

相關文章