以 OSGi 包的形式开发和部署 Web 服务
簡介
OSGi 是一個面向 Java 的動態(tài)模塊系統(tǒng)。OSGi Alliance(請參見?參考資料)發(fā)布了模塊系統(tǒng)的規(guī)范。一些受歡迎的 OSGi 容器包括 Eclipse Equinox(請參見?參考資料)和 Apache Felix 等等(請參見?參考資料)。作為一種用于開發(fā)和部署模塊化的、可重用的 Java 程序的框架,OSGi 呈現(xiàn)出強勁的發(fā)展勢頭。
OSGi 容器允許以 Jar 格式部署 Java 模塊(OSGi 將其稱為 “包”)。OSGi 的一個有趣的功能就是能夠把一個服務(wù)包的多個版本部署到同一個容器中。所有部署到 OSGi 容器中的包在一個 JVM 中運行。如果一個服務(wù)的客戶端位于這個 OSGi 容器的外部,那么這個服務(wù)包需要有分布式功能。Apache cxf-dosgi(請參見?參考資料)是一個新的服務(wù)框架,支持用于 OSGi 包的分布式功能。
當(dāng) Web 服務(wù)提供商開發(fā)了一個新版本的服務(wù)時,通常需要繼續(xù)支持現(xiàn)有的客戶機。因此,Web 服務(wù)提供商需要同時部署和維護多個版本的服務(wù)。OSGi 自然成為滿足這一需求的出色選擇。
自從 CXF 團隊發(fā)布了一個叫作 cxf-dosgi(支持對 OSGi 包進行分布)的新的框架以來,我選擇 Eclipse Equinox 作為 OSGi 的容器,并選擇 Apache CXF 作為 Web 服務(wù)框架。通過使用這個框架,我們可以把 Web 服務(wù)作為 OSGi 包進行開發(fā)和部署。由于一個包的多個版本能夠共存,因此人們可以同時部署和維護多個版本的 Web 服務(wù)。我將把 Apache Tomcat 作為一個 servlet 容器使用,用于部署客戶機。
在本文中,我將描述開發(fā) cxf-dosgi 服務(wù)包的詳細(xì)方法以及如何在 OSGi 容器中進行部署,并使用一個簡單的 Web 客戶機(和 OSGi 容器運行在不同的 JVM 中)對其進行訪問。我還將描述開發(fā)同一個服務(wù)的不同版本并把它部署到同一個 OSGi 容器中,以及演示該服務(wù)的兩個不同版本能夠共存并為多個類型的客戶機服務(wù)。
先決條件
首先下載并安裝 Eclipse 3.5(Galileo)。Eclipse 3.5 包含了一個叫作 Equinox(請參見?參考資料)的 OSGi 框架
然后下載 cxf-dosgi 單包發(fā)行版和 osgi compendium 包。下載這兩個包并保存到本地的同一個目錄中。請參見下面的?參考資料,以獲取下載鏈接。
下載并安裝 Apache Tomcat 5.5.9。我們將使用在 OSGi 容器(Eclipse)外部的 servlet 容器,用來安裝和運行我們的服務(wù)客戶機。
準(zhǔn)備 OSGi 容器
在開發(fā)一個分布式服務(wù)包之前,首先啟動容器并把 cxf-dosgi 注冊為服務(wù)提供商 enabler,從而為 OSGi 容器做準(zhǔn)備。
使用一個空的工作空間啟動 Eclipse 3.5。把 Perspective 設(shè)置為 “Plug-In Development”。一個 Eclipse 插件基本上就是一個 OSGi 包。
接下來使用菜單選項導(dǎo)入 cxf-dosgi osgi compendium 包以及 osgi compendium 包:
File/Import/Plug-In Development/Plug-ins and Fragments
然后選擇下載包所在的目錄。請參見?下面的圖 1。
圖 1. 導(dǎo)入所需的包。指定目錄位置
單擊 Next。在下一個對話框中,Eclipse 會顯示已下載的包。請參見?下面的圖 2?。
圖 2. 導(dǎo)入所需的包,選擇已下載的包
單擊?Add All?和?Finish。Eclipse 會自動創(chuàng)建兩個 Plug-In Development 項目,叫作?org.osgi.compendium?和?cxf-dosgi-ri-singlebundle-distribution。接下來我們需要把 osgi compendium 包作為所需的包指定到 dosgi 包中。雙擊?cxf-dosgi-ri-singlebundle-distribution?項目中的?META-INF/MANIFEST.MF?文件。當(dāng) Eclipse 在設(shè)計模式中打開清單文件時,選擇 Dependencies 選項卡,然后添加?org.osgi.compendium?作為 “Required Plug-ins”。現(xiàn)在您的 Eclipse 環(huán)境應(yīng)該如?圖 3?所示。
圖 3. 導(dǎo)入所需的包
OSGi 容器現(xiàn)在已經(jīng)為一些分布式服務(wù)部署做好了準(zhǔn)備。
開發(fā)一個服務(wù)包
接下來,我們將使用一個方法創(chuàng)建一個基于 POJO 的簡單 Web 服務(wù),叫作 DictionaryService。這個方法就是?lookupWord(string),它能返回一個字符串(單詞的含義)作為響應(yīng)。
要在 Eclipse 中創(chuàng)建一個服務(wù)包,首先要確保 Perspective 被設(shè)置為 “Plug-in Development”。創(chuàng)建一個叫作 DictionaryService 的新 Plug-in 項目。在創(chuàng)建項目時,選擇?com.demo.cxfdemo.Activator?作為包結(jié)構(gòu)。您可以在附帶包(cxf-dosgi-dw-article.zip 文件中的 DictionaryService_1.0.0.200908011529.jar)(請參見下面的?下載?鏈接)中找到?Activator.java, DictionaryService.java and DictionaryServiceImpl.java,使用它們替換由 Eclipse 創(chuàng)建的默認(rèn)的?Activator.java。雙擊 DictionaryService 項目中的?META-INF/MANIFEST.MF。Eclipse 應(yīng)該會顯示清單文件的設(shè)計視圖。單擊 Dependencies 選項卡,清除 Required Plug-ins,然后在 Imported Packages 中添加?org.osgi.framework。您的 Eclipse 會如下面的?圖 4?所示。
圖 4. 創(chuàng)建一個服務(wù)包
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 服務(wù)基本上就是一個 pojo(接口和實現(xiàn))。Activator 類設(shè)置服務(wù)屬性并注冊服務(wù)。特別值得一提的是,DictionaryService 不必實現(xiàn)或擴展任何 cxf 類。我們甚至不必把 dosgi 單包設(shè)置為一個必需的插件。通過應(yīng)用 cxf-dosgi,在執(zhí)行 Run 配置時,它將被作為一個 cxf Web 服務(wù)進行部署。
部署服務(wù)包
下一步是部署和運行服務(wù)包。為此,我們需要創(chuàng)建一個 Run Configuration。右鍵單擊?DictionaryService項目,然后選擇?Run As/Run Configurations。在名為 demo_dosgi 的 OSGi Framework 文件夾中創(chuàng)建一個新的配置。您的 Run Configuration 彈出對話框應(yīng)該如?圖 5?所示。
圖 5. Run 配置
單擊?Apply?和?Run。現(xiàn)在 Eclipse 會啟動它內(nèi)部的 OSGi 框架(Equinox),安裝和啟動工作空間的三個包。您的 Eclipse 環(huán)境現(xiàn)在應(yīng)該如?圖 6?所示。
圖 6. 運行包
注意,Eclipse 不會自動顯示 osgi> 提示。單擊一下 Console 窗口會得到此提示。在這個提示中運行命令 ss(短暫狀態(tài)),查看包的狀態(tài)。要獲得其他可用命令清單,在提示中運行 ?。上面的顯示也可以確認(rèn)服務(wù)端點 URL?http://localhost:9000/DictionaryService?是否可用。還可以通過在瀏覽器中運行 URL?http://localhost:9000/DictionaryService?wsdl?來確認(rèn)這一點,現(xiàn)在這個瀏覽器應(yīng)該顯示 WSDL 內(nèi)容。把這個 xml 文檔作為?DictionaryService.wsdl?保存到一個臨時文件夾中。在下一小節(jié),我們將使用它生成一個客戶機。
開發(fā) Web 客戶機以調(diào)用服務(wù)
要調(diào)用新部署的 Web 服務(wù),現(xiàn)在讓我們創(chuàng)建一個簡單的 Web 應(yīng)用程序客戶機。在 Eclipse 中切換到 Java EE Perspective,創(chuàng)建一個叫作?DictionaryServiceClient?的新的 Dynamic Web Application 項目。把?DictionaryService.wsdl?復(fù)制到 WebContent 文件夾中。右鍵單擊 DictionaryService.wsdl 文件,然后選擇?Web Services/Generate Client。現(xiàn)在 Eclipse 應(yīng)該已經(jīng)在包名為?com.demo.cxfdosgi的 src 文件夾中創(chuàng)建了一組客戶機 Java 文件?,F(xiàn)在我們創(chuàng)建一個 jsp 文件?dictionaryServiceClient.jsp,用來調(diào)用這個服務(wù)代理,如下面的?清單 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?項目,然后導(dǎo)出一個 war 文件?DictionaryServiceClient.war。把這個文件復(fù)制到?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 中運行,我們已經(jīng)用一個分布式客戶機測試了服務(wù)包。注意:把 Tomcat 的 HTTP 端口設(shè)置為 8082,這是因為 Eclipse 已經(jīng)在使用 8080 部署 cxf Web 服務(wù)。
新版的服務(wù)包
把 Web 服務(wù)作為一個 OSGi 包進行部署的一個有趣功能就是可以同時部署一個 Web 服務(wù)的多個版本?,F(xiàn)在讓我們開發(fā) DictionaryService 的下一個版本:DictionaryServiceV2。DictionaryServiceV2 的 lookupWord 方法能夠返回兩個字符串?dāng)?shù)組,一個表示單詞的釋義,另一個包含該詞的同義詞。由于我們修改了方法簽名,顯然已經(jīng)破壞了現(xiàn)有客戶機。通過把修改后的 Web 服務(wù)作為一個獨立的包進行部署,我們使舊客戶機能夠繼續(xù)運行,同時使新客戶機能夠使用服務(wù)的新版本。
在 Eclipse 中切換到 Plug-in Development Perspective,使用三個文件創(chuàng)建一個叫作?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 窗口應(yīng)該如?圖 7?所示。
圖 7. 創(chuàng)建 DictionaryServiceV2 包
編輯 demo_dosgi Run 配置,確保配置中包含了?DictionaryServiceV2?包,如?圖 8?所示。
圖 8. 修改后的 Run 配置
單擊?Apply?和?Run。現(xiàn)在 Eclipse 會重新啟動 OSGi 框架,安裝第四個包(DictionaryServiceV2),然后啟動所有的四個包?,F(xiàn)在您的 Eclipse 會如?圖 9?所示。
圖 9. 運行包
這將確認(rèn)所有的四個包都已安裝并且正在運行。日志消息也可以確定服務(wù)端點:
http://localhost:9000/DictionaryService?和
http://localhost:9000/DictionaryServiceV2
處于激活狀態(tài)。在瀏覽器中訪問第二個服務(wù),如?http://localhost:9000/DictionaryServiceV2?wsdl,然后把顯示的 wsdl 內(nèi)容保存到文件?DictionaryServiceV2.wsdl?中。
調(diào)用新服務(wù)
要調(diào)用新版本的 Web 服務(wù),我們需要生成一個新的客戶機。創(chuàng)建一個新的項目?DictionaryServiceV2Client?作為一個 Dynamic web Application。使用與第一個版本相同的步驟復(fù)制 wsdl 并生成 Java 客戶機。創(chuàng)建一個新的 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 導(dǎo)出,然后把它安裝到運行在 Eclipse 外部的 tomcat 服務(wù)器中。現(xiàn)在在瀏覽器中訪問?http://localhost:8082/DictionaryServiceV2Client/dictionaryServiceV2Client.jsp?時應(yīng)該顯示為:
| 1 2 | ?? DictionaryService response = whatisthis means...? ?? DictionaryService response = Synonyms:... |
現(xiàn)在我們已經(jīng)成功地開發(fā)、部署和測試了一個 Web 服務(wù)的兩個版本。
結(jié)束語
在本文中,我沒有使用 pojo 服務(wù)包中的任何 cxf-dosgi API 類。然而,可以通過編輯 manifest.mf 文件(前面的 “導(dǎo)入包” 部分),導(dǎo)入指定包來使用 cxf-dosgi 類。注意,所有 J2SE 類本質(zhì)上說都可用于一個包。但是,要從一個服務(wù)包中使用任何 JEE 服務(wù)(如發(fā)送郵件等),您需要通過編輯 manifest.mf 來導(dǎo)入具體的 JEE 包。Eclipse 提供了大部分可導(dǎo)入的 JEE 包。
我已經(jīng)描述了把 Web 服務(wù)作為一個 OSGi 包進行開發(fā)和部署以及使用一個簡單的 web 應(yīng)用程序客戶機調(diào)用服務(wù)的詳細(xì)方法。我還討論了 SOA 策略對于在一個整潔的 OSGi 容器環(huán)境中同時部署和支持一個服務(wù)的多個版本的好處。
下載資源
- 用于本文的 Service 和 Client 包?(cxf-dosgi-dw-article.zip | 3,562KB)
相關(guān)主題
- 在?OSGi Alliance?中了解更多有關(guān) OSGi 規(guī)范的內(nèi)容。
- 查看一些受歡迎的 OSGi 容器 “Eclipse Equinox” 和 “Apache Felix”。
- “Web 服務(wù)版本控制最佳實踐”(developerWorks,2004 年 1 月):在本文中,Kyle Brown 和 Michael Ellis 將概述 Web 服務(wù)開發(fā)人員所面對的版本控制困難的范圍,并且提供一些解決方案模板,討論解決這個問題的體系結(jié)構(gòu)和最佳實踐。。
- “Designing and versioning compatible Web services”,面向 Web 服務(wù)版本控制的策略。
- “Eclipse IDE for Java EE Developers”,下載 Eclipse 3.5(包括 Equinox),用于開發(fā)和部署 OSGi 包。
- “Apache cxf-dosgi”,下載 Apache cxf-dosgi 單包發(fā)行版(jar)。
- “OSGi Compendium 包”,用于 cxf-dosgi 的包。
- “Apache Tomcat 5.5.9”,用來部署調(diào)用 OSGi 服務(wù)包的 web 客戶機的 Servlet 容器。
- 下載?IBM 產(chǎn)品評估版?或?在線試用 IBM SOA Sandbox,并開始使用來自 DB2?、Lotus?、Rational?、Tivoli? 和 WebSphere? 的應(yīng)用程序開發(fā)工具和中間件產(chǎn)品。
- developerWorks SOA and Web services 專區(qū):讓您了解更多和 SOA 以及 Web 服務(wù)相關(guān)的內(nèi)容,包括技術(shù)文章、教程以及特殊專題等。
from:?https://www.ibm.com/developerworks/cn/webservices/ws-OSGi/index.html?
總結(jié)
以上是生活随笔為你收集整理的以 OSGi 包的形式开发和部署 Web 服务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于 OSGi 的面向服务的组件编程
- 下一篇: OSGi入门篇:模块层