OSGi 和 Spring,第 1 部分: 使用 Apache Felix 構建和部署 OSGi 包

火星人 @ 2014-03-12 , reply:0


  
開發、構建並將 Java™ 類組件打包為開放服務網關協議(Open Services Gateway Initiative,OSGi)包,將其部署在 Apache Felix 運行時環境中。然後,使用 Felix Shell 命令啟動和停止包及對其進行動態更新。

引言

本文是本系列的第 1 部分,我們將開發包含客戶端和伺服器端組件的訂單應用程序。然後將這些組件打包為 OSGi 包。客戶端調用服務組件處理訂單。服務組件具有處理訂單和列印訂單 ID 的方法。閱讀本文後,您可以應用 Apache Felix 的概念和功能來將 Java 組件類構建和打包為 OSGi 包。

系統要求

要運行本文中的示例,請確保已在計算機上安裝和設置了以下軟體:

  • Java 5 或更高版本
  • Ant 構建工具
  • Apache Felix 二進位分發版 1.0.4

接下來,設置以下環境變數(按照示例 ANT_HOME=C:\apache-ant-1.7.0 進行設置):

  • JAVA_HOME(用於 Java)
  • ANT_HOME(用於 Ant)

接下來,將以下內容添加到 PATH 環境變數:

  • JAVA_HOME\bin
  • ANT_HOME\bin




OSGi

OSGi 規範以更為動態的方式定義和傳播 Java 應用程序的模塊化。通常,Java 應用程序模塊化為 JAR 包。但是使用 JAR 文件有局限性:

  • JAR 包通過類路徑環境變數解析,而這並未提供管理 JAR 依賴關係的可靠框架。
  • JAR 無法進行版本控制,因此無法跟蹤所創建或修改的 JAR 包的歷史。
  • 沒有用於在運行時出現代碼更改的情況下動態更新 JAR 文件的框架。

為了處理上述問題,可以使用 OSGi 框架,因為其中對 Java 的模塊化系統進行了重新定義。相對於傳統的 JAR 模塊而言,基於 OSGi 的系統具有以下優勢:

  • OSGi 提供了可靠的集成環境,包可以在其中作為服務發布並導出供其他包使用。
  • OSGi 為每個新組件提供了包版本控制功能。因此可以跟蹤包創建和更改的歷史。
  • 通過 OSGi,可以在運行時出現更改的情況下隨時動態更新包。

目前有三個已知的 OSGi 實現:

  • Equinox
  • Knopflerfish
  • Felix

本系列文章將介紹如何將 Felix 作為 OSGi 容器使用。本系列文章涵蓋以下主題:

  • 第 1 部分介紹如何使用 OSGi API 進行組件開發。
  • 第 2 部分將重點介紹在 OSGi 容器中使用 Spring 和從組件類消除 OSGi API 依賴關係,從而使其成為傳統 Java 對象(plain old Java objects,POJO)。這樣做的優勢在於,只需將重點放在編寫組件類中的業務方法上,而由 Spring 配置文件處理組件的生命周期。




訂單應用程序

接下來讓我們看看如何使用基於 Felix 的 OSGi 框架創建訂單應用程序包。此應用程序包括兩個組件:OrderClient.java(客戶端)和 OrderService.java(伺服器端)。客戶端組件打包為 client.jar,伺服器組件打包為 order.jar。接下來讓我們首先看看 OrderClient 類。


清單 1. 客戶端組件 OrderClient
public class OrderClient implements BundleActivator {      private ServiceTracker orderTracker;    private OrderService orderService;      public void setService(OrderService orderService) {      this.orderService = orderService;    }      public void removeService() {      this.orderService = null;    }      public void start(BundleContext context) throws Exception {     orderTracker =      new ServiceTracker(context, OrderService.class.getName(), null);     orderTracker.open();     OrderService order = (OrderService) orderTracker.getService();       if (order == null) {       System.out.println("Order service not available");     } else {       order.processOrder();     }    }      public void stop(BundleContext context) {     System.out.println("Bundle stopped");     orderTracker.close();   }    }  

正如清單 1 中所示,OrderClient 對 OrderService 組件調用 processOrder 方法,以在啟動 client.jar 包時列印 orderID。此類實現 BundleActivator 介面,該介面具有兩個回調方法:start() 和 stop()。啟動和停止客戶端包時,Felix 容器將調用實現的 start() 和 stop() 方法。

接下來讓我們仔細分析一下 start() 方法。在 start() 方法中,首先獲得 ServiceTracker 類的引用。您可以將此類視為工廠類。然後通過調用此 getService 方法從此工廠類獲取服務引用。ServiceTracker 使用以下參數構造:包上下文和 OrderService 類的名稱。


清單 2. OrderService 實現
public class OrderServiceImpl implements OrderService, BundleActivator {      private ServiceRegistration registration;      public void start(BundleContext context) {     registration =      context.registerService(OrderService.class.getName(), this, null);     System.out.println("Order Service registered");   }      public void stop(BundleContext context) {     System.out.println("Order Service stopped");   }      public void processOrder() {     System.out.println("Order id: ORD123") ;    }  }  

伺服器端 order.jar 文件包含兩個組件:OrderService 介面和 OrderServiceImpl 類。此介面具有由 OrderServiceImpl 類實現的抽象類 processOrder。此類還實現了 BundleActivator 介面,此介面供 Felix 容器調用來啟動和停止 order.jar 包。start() 方法在註冊中心註冊 OrderService 組件,以供客戶端包使用。註冊與導出對象供其他包使用的作用一樣。





通過 Manifest 通信

真正的問題是,客戶端包如何知道註冊的服務包?此通信通過使用 Manifest 文件處理。在 Manifest 文件中,在導入和導出程序包中提供包的引用。客戶端包 Manifest 通常導入服務組件程序包,而服務包 Manifest 導出自己的程序包。請注意,當包 A 導入包 B 的程序包時,包 B 必須導出自己的程序包。沒有恰當的導入和導出定義,通信將失敗。


清單 3. 客戶端清單文件
Manifest-Version: 1.0  Bundle-ManifestVersion: 2  Bundle-Name: Order Service Client  Bundle-SymbolicName: orderclient  Bundle-Version: 1.0.0  Bundle-Activator: order.client.OrderClient  Import-Package: org.osgi.framework, org.osgi.util.tracker, order  


清單 4. 伺服器清單文件
Manifest-Version: 1.0  Bundle-ManifestVersion: 2  Bundle-Name: Order Service  Bundle-SymbolicName: orderservice  Bundle-Version: 1.0.0  Export-Package: order  Bundle-Activator: order.impl.OrderServiceImpl  Import-Package: org.osgi.framework  

對於訂單應用程序,client.jar 包 Manifest 中包含條目 Import-Package: org.osgi.framework, org.osgi.util.tracker, order。這個實際上表示,客戶端包導入核心 OSGi 程序包和 OrderService 程序包。類似地,order.jar 包清單包含條目 Export-Package: order。即,包導出其程序包供客戶端使用。如果導入和導出未顯式聲明,OSGi 將引發運行時錯誤。

Manifest 文件還包含其他信息,如包激活器類的名稱等。激活器類負責在包中調用 start() 和 stop() 方法。在本例中,client.jar 包的激活器類為 OrderClient,order.jar 包的激活器類為 OrderService。





部署

在部署和使用包前,請進行以下工作:

  1. 根目錄 C:\osgi 文件夾下創建圖 1 中所示的目錄結果,並將本文前面介紹的組件放入其中:
    • Java 代碼放入相應的程序包文件夾(客戶端和服務)。
    • 清單文件放入相應的 META-INF 文件夾(客戶端和服務)。


    圖 1. 代碼目錄結構


下一步便是部署這些包。請通過以下步驟,使用 Felix OSGi 容器部署客戶端和服務包:

  1. 在服務文件夾中使用 ANT 運行 build.xml。
  2. 在客戶端文件夾中使用 ANT 運行 build.xml。

執行了上述構建文件后,將分別在 client/bin 和 service/bin 文件夾中創建 client.jar 和 order.jar 包。

  1. 在 Microsoft® Windows® 命令提示符中運行 startfelix.bat,以啟動 Felix 運行時。

每次啟動 Felix 運行時,都會提示配置文件名稱。配置文件名稱的作用類似於項目名稱。可以提供任何名稱作為項目配置文件的名稱。對於 Felix 運行時的每次後續啟動,如果提供了之前輸入的相同配置文件名稱,Felix 將會載入與該項目名稱關聯的所有已安裝包。如果提供了新配置名稱,則將需要再次顯式安裝各個包:

  1. 在 Felix Shell 中提供以下命令,以安裝各個包:
    • install file:service/bin/order.jar
    • install file: client/bin/client.jar
    • start service_bundle_id
    • start client_bundle_id

為了指示包的 ID,可以使用 ps 命令。必須首先啟動服務包,然後啟動客戶端包。在啟動相應的包時,將顯示以下輸出(請參見圖 2)。


圖 2. 程序輸出

還可以通過在 Felix Shell 提供 update bundle_id 命令更新包。包將在運行時動態更新。





結束語

本文簡單介紹了 OSGi 框架的功能和概念,並說明了如何使用其創建動態 JAR 包。您了解了如何構建並將組件打包為 OSGi 包,然後在 Felix 運行時環境中運行。我們還了解了如何創建包 Manifest 文件,以作為包之間的通信介面使用。

OSGi 提供了一種新的構建和管理 JAR 包的方式。請繼續關注本系列的第 2 部分,我們將介紹 Spring 框架在 OSGi 環境中如何代替 OSGi 承擔管理包的責任。(責任編輯:A6)





[火星人 via ] OSGi 和 Spring,第 1 部分: 使用 Apache Felix 構建和部署 OSGi 包已經有133次圍觀

http://www.coctec.com/docs/linux/show-post-69023.html