【IT168 技术文章】
引言
在过去数年里,随着万维网联盟(World Wide Web Consortium,W3C)更新了核心规范,并引入了弥补 Web 服务最初缺陷的新规范,Web 服务发生了大量的变化。W3C 的 Web Services Activity 小组所维护的规范以独立于供应商的方式将 Web 服务作为一组 XML 规范进行处理。
同时,Java™ Community Process (JCP) 也在维护自己的规范集,以将 W3C 的建议合并到 Java 语言中。Java APIs for XML(JAX-RPC、JAXB、JAXP、JAXR 和 SAAJ)是一组使用 Java 语言实现 Web 服务规范的接口。
W3C 所维护的当前 Web 服务规范和 JCP 维护的 Java Web 服务 API 处理“网络上”的 Web 服务,以确保平台独立性和语言独立性。遵循 XML 规范或使用 Java API 的开发人员将确保应用程序能够通过任何通信协议在任何平台上与采用任何语言编写的 Web 服务进行通信。Web 服务可扩展任何应用程序的访问范围,是经过验证的对目前基于 Web 的应用程序有价值的集成技术。
但当基于 Web 的应用程序需要跨多个 Web 应用程序容器(如 IBM® WebSphere® Application Server、BEA WebLogic 和 Tomcat 等,这里仅指出三个)部署时,跨网络兼容性不够。对于 Java Web 服务,没有跨多个 Web 应用程序容器实现的标准部署的“web.xml”可用。
如果您希望应用程序支持多个 Web 应用程序容器提供的 Web 服务实现,则 Java Web 服务应用程序的部署可能会成为一项挑战。可以在 Web 应用程序中使用单个 Web 服务实现,如来自 Apache Web 服务项目的 Axis。对于 Web 服务客户机,这个策略通常能跨多个 Web 容器工作,因为客户机代码并不依赖于任何 Web 服务部署描述符。对于 Web 服务提供者(服务器),如果将 Web 服务实现嵌入 Web 应用程序存档(Web Application Archive,war)文件中,可能会导致意外加载器冲突,因此使用供应商的 Web 服务实现是最理想的部署选择。
本文剩下的部分将讨论 Java Web 服务的部署问题,向您展示各种部署描述符实现,并讨论 Java 社区如何开始处理这个问题。
开发跨多个容器部署的单个 Web 服务
对于 Web 应用程序部署,我们希望进行开放性的选择。如果您的客户在 WebSphere 或 WebLogic 等商业 J2EE 实现进行了投资,他们将希望利用其投资的平台。另一方面,如果您的客户希望降低初期投入成本,则可能希望采用 JBoss 或 Apache Tomcat 等开放源代码解决方案。在这两种情况下,如果您希望尽可能提高开发工作的可重用性,则可能无法依赖于可用的供应商特定 IDE。使用 J2EE 应用程序供应商提供的 IDE 进行开发工作可能会限制处理 Java Web 服务时的灵活性,隐藏部署 Web 服务的很多细节。
本文中的示例使用开放源代码社区提供的免费标准的开发工具集来为每个目标 Web 应用程序容器构建 Web 服务部署描述符。所有这些工具均在开发人员中得到了广泛应用,且支持各种开放标准技术。
我们的目标是,获得能够生成可使用 Axis 跨目标 Web 应用程序容器(WebSphere、WebLogic、JBoss 和 Tomcat)部署的 Web 服务的单个项目。相应的 war 文件应该能够在只需很少修改而绝对不需要重新编译源代码的情况下部署到我们的目标 Web 应用程序容器上。
本文并不打算作为有关 Web 服务或 Web 服务部署的教程,而旨在说明 Java Web 服务的一个问题,并阐述将来可以如何处理这个问题。如果您仅使用一个 Web 应用程序容器,而没有打算更改 Web 应用程序容器,则可以跳过有关 Web Services Metadata (JSR-181) 的部分(此 JSR 可能会影响您将来的开发工作)。
Web 服务的描述
为了提供有关我们的部署示例的足够信息,我创建了一个需要为接口使用映射文件的 Web 服务。传统的 Hello World 或 Stock Ticker Web 服务将无法提供足够的信息来说明我们的 Web 服务部署需求。
我们的 Web 服务端点将具有多个方法,这些方法可用于说明部署期间所需的各种文件。我们的示例 Web 服务将返回有关远程应用程序性能的信息。当然,我们的示例实现并不会返回任何实际的信息,它只不过是一个简单的示例,用于说明更为复杂的 Web 服务接口的要求。下面是用于创建我们的 Web 服务端点的接口文件。
清单 1. Web 服务端点接口
2 public StatsContainer[] getAllStatistics() throws java.rmi.RemoteException;
3 public StatsContainer[] getStatistics(String category) throws java.rmi.RemoteException;
4 public void resetAllStatistics() throws java.rmi.RemoteException;
5 public void resetStatistics(String category) throws java.rmi.RemoteException;
6 public void clearStatistics() throws java.rmi.RemoteException;
7 public String[] getCategories() throws java.rmi.RemoteException;
8 }
9
此接口具有两个不同的返回类型,需要进行映射。第一个类型是 StatsContainer 对象数组,而另一个类型则是 string 对象数组。StatsContainer 是简单容器对象,该对象具有若干基元类型和两个字符串。我们的目标是,从此接口和实现文件入手,使用我们的开放工具集中提供的工具构建所需的部署描述符,以便将 Web 服务部署到目标平台上。我们将描述此过程中的每个步骤以及生成的各个文件。
构建过程的描述
我们的 Web 服务的构建过程中将使用各种自动化工具,这些工具由可利用 Java 自检构建 Web 服务构件的 Web 服务实现提供。对于我们的部署,将使用两种不同的构建工具,因为部署描述符分属两个不同的组:支持 J2EE 1.4 的部署描述符和自定义 Web 服务部署描述符。
J2EE 1.4 Web 服务
为了构建标准 J2EE 1.4 Web 服务所需的构件,我们使用了 Java Web Service Developers Pack (JWSDP v1.5) 所提供的 wscompile 命令。wscompile 命令会创建 Web 服务描述语言(Web Service Description Language,WSDL)文件、Web 服务映射文件和实现文件,以便在 Web 服务和调用的应用程序之间进行封送处理。
为了运行 wscompile 命令,您首先需要编写一个 XML 配置文件,在其中描述您希望 wscompile 执行的操作。在此示例中,我们希望处理我们的服务端点并创建实现所需的 XML 构件和序列化代码。下面是 wscompile 命令所需的配置文件的示例:
清单 2. 示例配置文件
2
3 <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
4 <service name="StatsWS"
5 targetNamespace="http://services.symmetrysolutions.com/stats"
6 typeNamespace="http://types.symmetrysolutions.com/stats"
7 packageName="com.symmetrysolutions.statsws">
8 <interface name="com.symmetrysolutions.statsws.StatsService"
9 servantName="com.symmetrysolutions.statsws.StatsServiceImpl"/>
10 </service>
11 </configuration>
12
在此配置文件中,我们使用 service 元素描述我们的 Web 服务。此元素告知 wscompile 命令以下内容:将与接口关联的命名空间以及与该接口关联的类型。除了命名空间外,service 元素还告知 wscompile 命令为生成的任何源代码使用的包名称以及其将自检的接口的名称。
运行自动化工具并不是部署符合 J2EE 1.4 的 Web 服务的最后一步。根据所使用的 Web 应用程序容器的不同,最后的步骤将有所变化。无论在何种情况下,必须包含的最后一个 Web 服务部署构件都是 webservices.xml 文件。此文件告知 J2EE 1.4 应用程序容器在何处查找 Web 服务描述,以及将什么接口和实现类用于 Web 服务。
Axis Web 服务
Axis Web 服务的构建过程与 J2EE 1.4 Web 服务不同,因为 Axis 具有自己的部署描述符。Axis Web 服务运行时需要 deploy.wsdd 文件提供的信息,以确定服务端点的名称和将其作为 Web 服务发布的方式。deploy.wsdd 文件将发送到 Axis 服务器,Axis 服务器将利用此信息对 Web 服务进行自检,并创建 Web 服务运行时所需的信息。注意:上述过程并不符合 J2EE 1.4 (部署构件),但符合 SOAP 1.1,因此 Axis Web 服务将能够与任何 Web 服务客户机进行互操作。
要构建 Axis Web 服务部署描述符,可以手动进行,也可以使用 Axis WSDL2Java Ant 任务来处理 Web 服务的 WSDL。在我们的示例中,由于我们决定使用 Web 服务端点的接口,因此没有 WSDL 文件。幸运的是,Axis 还提供了一个 Ant 任务来处理接口并输出 WSDL 文件。因此,Axis 构建过程包含两个步骤,如下所述:
使用 Java2WSDL 任务从接口创建 WSDL 文件。
从 WSDL 创建 Web 服务框架(本文中将不使用)和部署描述符(将在本文中使用)。
构建了 Axis Web 服务后,必须告知 Web 应用程序容器要部署的服务以及如何进行部署,以便进行部署。这是通过将 deploy.wsdd 文件传递给部署 Web 服务的 Axis 管理员任务来完成的。这意味着,在 Web 容器启动后,Axis Web 服务需要进行部署 Web 服务的步骤。