以 OSGi 包的形式开发和部署 Web 服务
簡介
OSGi 是一個面向 Java 的動態模塊系統。OSGi Alliance(請參見?參考資料)發布了模塊系統的規范。一些受歡迎的 OSGi 容器包括 Eclipse Equinox(請參見?參考資料)和 Apache Felix 等等(請參見?參考資料)。作為一種用于開發和部署模塊化的、可重用的 Java 程序的框架,OSGi 呈現出強勁的發展勢頭。
OSGi 容器允許以 Jar 格式部署 Java 模塊(OSGi 將其稱為 “包”)。OSGi 的一個有趣的功能就是能夠把一個服務包的多個版本部署到同一個容器中。所有部署到 OSGi 容器中的包在一個 JVM 中運行。如果一個服務的客戶端位于這個 OSGi 容器的外部,那么這個服務包需要有分布式功能。Apache cxf-dosgi(請參見?參考資料)是一個新的服務框架,支持用于 OSGi 包的分布式功能。
當 Web 服務提供商開發了一個新版本的服務時,通常需要繼續支持現有的客戶機。因此,Web 服務提供商需要同時部署和維護多個版本的服務。OSGi 自然成為滿足這一需求的出色選擇。
自從 CXF 團隊發布了一個叫作 cxf-dosgi(支持對 OSGi 包進行分布)的新的框架以來,我選擇 Eclipse Equinox 作為 OSGi 的容器,并選擇 Apache CXF 作為 Web 服務框架。通過使用這個框架,我們可以把 Web 服務作為 OSGi 包進行開發和部署。由于一個包的多個版本能夠共存,因此人們可以同時部署和維護多個版本的 Web 服務。我將把 Apache Tomcat 作為一個 servlet 容器使用,用于部署客戶機。
在本文中,我將描述開發 cxf-dosgi 服務包的詳細方法以及如何在 OSGi 容器中進行部署,并使用一個簡單的 Web 客戶機(和 OSGi 容器運行在不同的 JVM 中)對其進行訪問。我還將描述開發同一個服務的不同版本并把它部署到同一個 OSGi 容器中,以及演示該服務的兩個不同版本能夠共存并為多個類型的客戶機服務。
先決條件
首先下載并安裝 Eclipse 3.5(Galileo)。Eclipse 3.5 包含了一個叫作 Equinox(請參見?參考資料)的 OSGi 框架
然后下載 cxf-dosgi 單包發行版和 osgi compendium 包。下載這兩個包并保存到本地的同一個目錄中。請參見下面的?參考資料,以獲取下載鏈接。
下載并安裝 Apache Tomcat 5.5.9。我們將使用在 OSGi 容器(Eclipse)外部的 servlet 容器,用來安裝和運行我們的服務客戶機。
準備 OSGi 容器
在開發一個分布式服務包之前,首先啟動容器并把 cxf-dosgi 注冊為服務提供商 enabler,從而為 OSGi 容器做準備。
使用一個空的工作空間啟動 Eclipse 3.5。把 Perspective 設置為 “Plug-In Development”。一個 Eclipse 插件基本上就是一個 OSGi 包。
接下來使用菜單選項導入 cxf-dosgi osgi compendium 包以及 osgi compendium 包:
File/Import/Plug-In Development/Plug-ins and Fragments
然后選擇下載包所在的目錄。請參見?下面的圖 1。
圖 1. 導入所需的包。指定目錄位置
單擊 Next。在下一個對話框中,Eclipse 會顯示已下載的包。請參見?下面的圖 2?。
圖 2. 導入所需的包,選擇已下載的包
單擊?Add All?和?Finish。Eclipse 會自動創建兩個 Plug-In Development 項目,叫作?org.osgi.compendium?和?cxf-dosgi-ri-singlebundle-distribution。接下來我們需要把 osgi compendium 包作為所需的包指定到 dosgi 包中。雙擊?cxf-dosgi-ri-singlebundle-distribution?項目中的?META-INF/MANIFEST.MF?文件。當 Eclipse 在設計模式中打開清單文件時,選擇 Dependencies 選項卡,然后添加?org.osgi.compendium?作為 “Required Plug-ins”。現在您的 Eclipse 環境應該如?圖 3?所示。
圖 3. 導入所需的包
OSGi 容器現在已經為一些分布式服務部署做好了準備。
開發一個服務包
接下來,我們將使用一個方法創建一個基于 POJO 的簡單 Web 服務,叫作 DictionaryService。這個方法就是?lookupWord(string),它能返回一個字符串(單詞的含義)作為響應。
要在 Eclipse 中創建一個服務包,首先要確保 Perspective 被設置為 “Plug-in Development”。創建一個叫作 DictionaryService 的新 Plug-in 項目。在創建項目時,選擇?com.demo.cxfdemo.Activator?作為包結構。您可以在附帶包(cxf-dosgi-dw-article.zip 文件中的 DictionaryService_1.0.0.200908011529.jar)(請參見下面的?下載?鏈接)中找到?Activator.java, DictionaryService.java and DictionaryServiceImpl.java,使用它們替換由 Eclipse 創建的默認的?Activator.java。雙擊 DictionaryService 項目中的?META-INF/MANIFEST.MF。Eclipse 應該會顯示清單文件的設計視圖。單擊 Dependencies 選項卡,清除 Required Plug-ins,然后在 Imported Packages 中添加?org.osgi.framework。您的 Eclipse 會如下面的?圖 4?所示。
圖 4. 創建一個服務包
Activator.java, DictionaryService.java and DictionaryServiceImpl.java?的源代碼如?清單 1所示。
清單 1. DictionaryService 包代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.demo.cxfdosgi; ? import java.util.Dictionary; import java.util.Hashtable; ? import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; ? public class Activator implements BundleActivator { ? ????private ServiceRegistration registration; ? ????public void start(BundleContext bc) throws Exception { ????????Dictionary<String, String> props = new Hashtable<String, String>(); ????????props.put("osgi.remote.interfaces", "*"); ????????props.put("osgi.remote.configuration.type", "pojo"); ????????props.put("osgi.remote.configuration.pojo.address", ??????????????????"http://localhost:9000/DictionaryService");??? ????? ????????registration = bc.registerService(DictionaryService.class.getName(), ??????????????????????????????????????????new DictionaryServiceImpl(), props);? ????} ? ????public void stop(BundleContext context) throws Exception { ????????registration.unregister(); ????} } ? package com.demo.cxfdosgi; ? public interface DictionaryService { ????? ????public String lookupWord(String word) throws Exception; ? } ? package com.demo.cxfdosgi; ? public class DictionaryServiceImpl implements DictionaryService { ? ????public String lookupWord(String word) throws Exception { ????????return word + " means..."; ????} ? } |
我們的 Web 服務基本上就是一個 pojo(接口和實現)。Activator 類設置服務屬性并注冊服務。特別值得一提的是,DictionaryService 不必實現或擴展任何 cxf 類。我們甚至不必把 dosgi 單包設置為一個必需的插件。通過應用 cxf-dosgi,在執行 Run 配置時,它將被作為一個 cxf Web 服務進行部署。
部署服務包
下一步是部署和運行服務包。為此,我們需要創建一個 Run Configuration。右鍵單擊?DictionaryService項目,然后選擇?Run As/Run Configurations。在名為 demo_dosgi 的 OSGi Framework 文件夾中創建一個新的配置。您的 Run Configuration 彈出對話框應該如?圖 5?所示。
圖 5. Run 配置
單擊?Apply?和?Run?,F在 Eclipse 會啟動它內部的 OSGi 框架(Equinox),安裝和啟動工作空間的三個包。您的 Eclipse 環境現在應該如?圖 6?所示。
圖 6. 運行包
注意,Eclipse 不會自動顯示 osgi> 提示。單擊一下 Console 窗口會得到此提示。在這個提示中運行命令 ss(短暫狀態),查看包的狀態。要獲得其他可用命令清單,在提示中運行 ?。上面的顯示也可以確認服務端點 URL?http://localhost:9000/DictionaryService?是否可用。還可以通過在瀏覽器中運行 URL?http://localhost:9000/DictionaryService?wsdl?來確認這一點,現在這個瀏覽器應該顯示 WSDL 內容。把這個 xml 文檔作為?DictionaryService.wsdl?保存到一個臨時文件夾中。在下一小節,我們將使用它生成一個客戶機。
開發 Web 客戶機以調用服務
要調用新部署的 Web 服務,現在讓我們創建一個簡單的 Web 應用程序客戶機。在 Eclipse 中切換到 Java EE Perspective,創建一個叫作?DictionaryServiceClient?的新的 Dynamic Web Application 項目。把?DictionaryService.wsdl?復制到 WebContent 文件夾中。右鍵單擊 DictionaryService.wsdl 文件,然后選擇?Web Services/Generate Client。現在 Eclipse 應該已經在包名為?com.demo.cxfdosgi的 src 文件夾中創建了一組客戶機 Java 文件?,F在我們創建一個 jsp 文件?dictionaryServiceClient.jsp,用來調用這個服務代理,如下面的?清單 2?所示:
清單 2. dictionaryServiceClient.jsp 代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <%@ page language="java" contentType="text/html; charset=ISO-8859-1" ????pageEncoding="ISO-8859-1" import="com.demo.cxfdosgi.DictionaryServicePortTypeProxy"%> ? <html> <body> <% DictionaryServicePortTypeProxy proxy = new DictionaryServicePortTypeProxy(); out.println("?? DictionaryService response = "+proxy.lookupWord("whatisthis")); %> </body> </html> |
右鍵單擊?DictionaryServiceClient?項目,然后導出一個 war 文件?DictionaryServiceClient.war。把這個文件復制到?C:/jakarta-tomcat-5.5.9/webapps?文件夾中。運行?C:/jakarta-tomcat-5.5.9/bin/startup.exe,然后訪問?http://localhost:8082/DictionaryServiceClient/dictionaryServiceClient.jsp。瀏覽器將顯示:
| 1 | ?? DictionaryService response = whatisthis means... |
由于 Eclipse 和 Tomcat 在兩個不同的 JVM 中運行,我們已經用一個分布式客戶機測試了服務包。注意:把 Tomcat 的 HTTP 端口設置為 8082,這是因為 Eclipse 已經在使用 8080 部署 cxf Web 服務。
新版的服務包
把 Web 服務作為一個 OSGi 包進行部署的一個有趣功能就是可以同時部署一個 Web 服務的多個版本?,F在讓我們開發 DictionaryService 的下一個版本:DictionaryServiceV2。DictionaryServiceV2 的 lookupWord 方法能夠返回兩個字符串數組,一個表示單詞的釋義,另一個包含該詞的同義詞。由于我們修改了方法簽名,顯然已經破壞了現有客戶機。通過把修改后的 Web 服務作為一個獨立的包進行部署,我們使舊客戶機能夠繼續運行,同時使新客戶機能夠使用服務的新版本。
在 Eclipse 中切換到 Plug-in Development Perspective,使用三個文件創建一個叫作?DictionaryServiceV2?的新的 Plug-in 項目。這三個文件分別是?Activator.java、DictionaryServiceV2.java 和 DictionaryServiceV2Impl.java,源代碼如下所示:
清單 3. DictionaryServiceV2 包代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.demo.cxfdosgi.v2; ? import java.util.Dictionary; import java.util.Hashtable; ? import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; ? public class Activator implements BundleActivator { ? ????private ServiceRegistration registration; ? ????public void start(BundleContext bc) throws Exception { ????????Dictionary<String, String> props = new Hashtable<String, String>(); ????????props.put("osgi.remote.interfaces", "*"); ????????props.put("osgi.remote.configuration.type", "pojo"); ????????props.put("osgi.remote.configuration.pojo.address", ??????????????????"http://localhost:9000/DictionaryServiceV2");??? ????? ????????registration = bc.registerService(DictionaryServiceV2.class.getName(), ??????????????????????????????????????????new DictionaryServiceV2Impl(), props);??? ????} ????? ????public void stop(BundleContext context) throws Exception { ????????registration.unregister(); ????} } ? package com.demo.cxfdosgi.v2; ? public interface DictionaryServiceV2 { ????? ????/** ?????* @param word - String, whose meaning and synonyms are requested ?????* @return String[] - where String[0] has the word meaning and ?????*????????????????????????? String[1] has synonyms ?????* @throws Exception ?????*/ ????public String[] lookupWord(String word) throws Exception; ? } ? package com.demo.cxfdosgi.v2; ? public class DictionaryServiceV2Impl implements DictionaryServiceV2 { ? ????public String[] lookupWord(String word) throws Exception { ????????// TODO Auto-generated method stub ????????String[] result = new String[2]; ????????? ????????result[0] = word + " means..."; ????????result[1] = "Synonyms:..."; ????????? ????????return result; ????} ? } |
您的 Eclipse 窗口應該如?圖 7?所示。
圖 7. 創建 DictionaryServiceV2 包
編輯 demo_dosgi Run 配置,確保配置中包含了?DictionaryServiceV2?包,如?圖 8?所示。
圖 8. 修改后的 Run 配置
單擊?Apply?和?Run?,F在 Eclipse 會重新啟動 OSGi 框架,安裝第四個包(DictionaryServiceV2),然后啟動所有的四個包?,F在您的 Eclipse 會如?圖 9?所示。
圖 9. 運行包
這將確認所有的四個包都已安裝并且正在運行。日志消息也可以確定服務端點:
http://localhost:9000/DictionaryService?和
http://localhost:9000/DictionaryServiceV2
處于激活狀態。在瀏覽器中訪問第二個服務,如?http://localhost:9000/DictionaryServiceV2?wsdl,然后把顯示的 wsdl 內容保存到文件?DictionaryServiceV2.wsdl?中。
調用新服務
要調用新版本的 Web 服務,我們需要生成一個新的客戶機。創建一個新的項目?DictionaryServiceV2Client?作為一個 Dynamic web Application。使用與第一個版本相同的步驟復制 wsdl 并生成 Java 客戶機。創建一個新的 jsp 文件?dictionaryServiceV2Client.jsp,如:
清單 4. dictionaryServiceV2Client.jsp 代碼
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <%@ page language="java" contentType="text/html; charset=ISO-8859-1" ????pageEncoding="ISO-8859-1" import="com.demo.cxfdosgi.v2.DictionaryServiceV2PortTypeProxy"%> ? <html> <body> <% DictionaryServiceV2PortTypeProxy proxy = new DictionaryServiceV2PortTypeProxy(); String[] resp = proxy.lookupWord("whatisthis"); out.println("?? DictionaryService response = "+resp[0]); %> <br/> <% out.println("?? DictionaryService response = "+resp[1]); %> </body> </html> |
把這個項目作為 DictionaryServiceV2Client.war 導出,然后把它安裝到運行在 Eclipse 外部的 tomcat 服務器中?,F在在瀏覽器中訪問?http://localhost:8082/DictionaryServiceV2Client/dictionaryServiceV2Client.jsp?時應該顯示為:
| 1 2 | ?? DictionaryService response = whatisthis means...? ?? DictionaryService response = Synonyms:... |
現在我們已經成功地開發、部署和測試了一個 Web 服務的兩個版本。
結束語
在本文中,我沒有使用 pojo 服務包中的任何 cxf-dosgi API 類。然而,可以通過編輯 manifest.mf 文件(前面的 “導入包” 部分),導入指定包來使用 cxf-dosgi 類。注意,所有 J2SE 類本質上說都可用于一個包。但是,要從一個服務包中使用任何 JEE 服務(如發送郵件等),您需要通過編輯 manifest.mf 來導入具體的 JEE 包。Eclipse 提供了大部分可導入的 JEE 包。
我已經描述了把 Web 服務作為一個 OSGi 包進行開發和部署以及使用一個簡單的 web 應用程序客戶機調用服務的詳細方法。我還討論了 SOA 策略對于在一個整潔的 OSGi 容器環境中同時部署和支持一個服務的多個版本的好處。
下載資源
- 用于本文的 Service 和 Client 包?(cxf-dosgi-dw-article.zip | 3,562KB)
相關主題
- 在?OSGi Alliance?中了解更多有關 OSGi 規范的內容。
- 查看一些受歡迎的 OSGi 容器 “Eclipse Equinox” 和 “Apache Felix”。
- “Web 服務版本控制最佳實踐”(developerWorks,2004 年 1 月):在本文中,Kyle Brown 和 Michael Ellis 將概述 Web 服務開發人員所面對的版本控制困難的范圍,并且提供一些解決方案模板,討論解決這個問題的體系結構和最佳實踐。。
- “Designing and versioning compatible Web services”,面向 Web 服務版本控制的策略。
- “Eclipse IDE for Java EE Developers”,下載 Eclipse 3.5(包括 Equinox),用于開發和部署 OSGi 包。
- “Apache cxf-dosgi”,下載 Apache cxf-dosgi 單包發行版(jar)。
- “OSGi Compendium 包”,用于 cxf-dosgi 的包。
- “Apache Tomcat 5.5.9”,用來部署調用 OSGi 服務包的 web 客戶機的 Servlet 容器。
- 下載?IBM 產品評估版?或?在線試用 IBM SOA Sandbox,并開始使用來自 DB2?、Lotus?、Rational?、Tivoli? 和 WebSphere? 的應用程序開發工具和中間件產品。
- developerWorks SOA and Web services 專區:讓您了解更多和 SOA 以及 Web 服務相關的內容,包括技術文章、教程以及特殊專題等。
from:?https://www.ibm.com/developerworks/cn/webservices/ws-OSGi/index.html?
總結
以上是生活随笔為你收集整理的以 OSGi 包的形式开发和部署 Web 服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于 OSGi 的面向服务的组件编程
- 下一篇: OSGi入门篇:模块层