OSGi是一个面向Java的动态模块系统。OSGi Alliance(请参见 参考资料)发布了模块系统的规范。一些受欢迎的OSGi容器包括EclipseEquinox(请参见 参考资料)和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。双击 ictionaryService项目中的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包代码
以下是引用片段: 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。现在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文件。现在我们创建一个jsp文件 ictionaryServiceClient.jsp,用来调用这个服务代理,如下面的 清单 2 所示:
清单 2. dictionaryServiceClient.jsp 代码
以下是引用片段: <%@ 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。浏览器将显示:
?? DictionaryService response = whatisthis means…
由于Eclipse和Tomcat在两个不同的JVM中运行,我们已经用一个分布式客户机测试了服务包。注意:把Tomcat的HTTP端口设置为8082,这是因为 Eclipse 已经在使用8080部署cxf Web服务。
新版的服务包
把Web服务作为一个OSGi包进行部署的一个有趣功能就是可以同时部署一个Web服务的多个版本。现在让我们开发DictionaryService的下一个版本:DictionaryServiceV2。DictionaryServiceV2的lookupWord方法能够返回两个字符串数组,一个表示单词的释义,另一个包含该词的同义词。由于我们修改了方法签名,显然已经破坏了现有客户机。通过把修改后的Web服务作为一个独立的包进行部署,我们使旧客户机能够继续运行,同时使新客户机能够使用服务的新版本。
在Eclipse中切换到Plug-in Development Perspective,使用三个文件创建一个叫作DictionaryServiceV2的新的Plug-in项目。这三个文件分别是Activator.java、DictionaryServiceV2.java和DictionaryServiceV2Impl.java,源代码如下所示:
清单 3. DictionaryServiceV2 包代码
以下是引用片段: 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。现在Eclipse会重新启动OSGi框架,安装第四个包(DictionaryServiceV2),然后启动所有的四个包。现在您的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代码
以下是引用片段: <%@ 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服务器中。现在在浏览器中访问 http://localhost:8082/DictionaryServiceV2Client/dictionaryServiceV2Client.jsp时应该显示为:
以下是引用片段: ?? 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容器环境中同时部署和支持一个服务的多个版本的好处。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
SAP收购CallidusCloud 与Salesforce竞争
一直被称为后台办公巨头的SAP现在似乎也想在前台办公大展拳脚。 最新的迹象是SAP收购CallidusClou […]
-
API设计如龙生九子 各不相同
IT咨询管理公司CA Technologies对API产业做了个问卷调查,问卷内容涉及API设计风格以及管理部署的新动向。调查结果表明,JSON与XML可谓两分天下。
-
既熟悉又陌生的开源项目
Eclipse基金会已成立整整10年了。目前这个开源组织拥有众多项目,其中就包含了最为出名的Java IDE Eclipse以及Mylyn。本文,我们将给您介绍10个已经“掀起波澜”的Eclipse项目。
-
OSGi中该使用Blueprint还是声明式服务?
在OSGi中,服务是实现bundle间交互和应用灵活性的基石。借助于服务,我们能够降低bundle之间的耦合,更加有利于软件的重用。