第 3 章 开发 Jakarta XML Web 服务


Jakarta XML Web 服务定义了 WSDL 和 Java 之间的映射,以及用于访问 Web 服务并发布它们的类。JBossWS 实施 Jakarta XML Web 服务 2.3,用户可以参考这些服务用于任何与供应商无关的 Web 服务使用需求。

3.1. 使用 Jakarta XML Web 服务工具

以下 Jakarta XML Web Services 命令行工具包含在 JBoss EAP 发行版中:这些工具可用于 服务器和 客户端开发

Expand
表 3.1. Jakarta XML Web Services 命令行工具
命令描述

wsprovide

生成 Jakarta XML Web 服务便携式工件,并提供抽象合同。用于底层开发.

wsconsume

使用抽象合同(WSDL 和架构文件),并为服务器和客户端生成工件。用于自上而下和客户端开发.

有关使用这些工具的更多详细信息,请参阅 Jakarta XML Web Services 工具

3.1.1. 服务器侧开发策略

在服务器端开发 Web 服务端点时,您可以选择从 Java 代码(称为 底部开发) 或 WSDL 开始,后者定义您的服务,称为 自上而下开发。如果这是一种新服务,即没有现有合同,则下向上的方法是最快的路线;您只需向类添加一些注释即可启动和运行服务。但是,如果您在开发服务时已定义了合同,使用自上而下的方法会更加简单,因为该工具可以为您生成注释的代码。

底部向上使用案例:

  • 将已存在的 Jakarta Enterprise Beans 3 bean 作为 Web 服务公开。
  • 提供新的服务,并且您希望为您生成合同。

上下使用案例:

  • 替换现有 Web 服务的实施,您不能破坏与旧客户端的兼容性。
  • 公开符合第三方指定合同的服务,例如供应商重新调用您已定义的协议。
  • 创建遵循预先开发的 XML 架构和 WSDL 的服务。
使用 wsprovide 的底部策略

底层策略涉及为您的服务开发 Java 代码,然后使用 Jakarta XML Web 服务 注释进行标注。这些注解可用于自定义为您的服务生成的合同。例如,您可以更改操作名称来映射到您喜欢的任何内容。但是,所有注释都具有明智的默认值,因此只需要 @WebService 注释。

这就像创建单个类一样简单:

package echo;

@javax.jws.WebService
public class Echo {

   public String echo(String input) {
      return input;
   }
}
Copy to Clipboard Toggle word wrap

可以使用此类构建部署,这是在 JBossWS 上部署的唯一 Java 代码。在部署时,会为您生成 WSDL 和所有其他 Java 构件,称为 wrapper 类

wsprovide 工具的主要用途是生成可移植 Jakarta XML Web Services 工件。此外,它也可用于为您的服务提供 WSDL 文件。这可以通过使用 -w 选项调用 wsprovide 来获取:

$ javac -d . Echo.java
$ EAP_HOME/bin/wsprovide.sh --classpath=. -w echo.Echo
Copy to Clipboard Toggle word wrap

检查 WSDL 会显示一个名为 EchoService 的服务

<wsdl:service name="EchoService">
  <wsdl:port name="EchoPort" binding="tns:EchoServiceSoapBinding">
    <soap:address location="http://localhost:9090/EchoPort"/>
  </wsdl:port>
</wsdl:service>
Copy to Clipboard Toggle word wrap

如预期的那样,该服务会定义一个操作,echo:

<wsdl:portType name="Echo">
  <wsdl:operation name="echo">
    <wsdl:input name="echo" message="tns:echo">
    </wsdl:input>
    <wsdl:output name="echoResponse" message="tns:echoResponse">
    </wsdl:output>
  </wsdl:operation>
</wsdl:portType>
Copy to Clipboard Toggle word wrap

在部署时,您不需要运行此工具。您只需要为服务生成可移植工件或抽象合同即可。

可在简单的 web.xml 文件中为部署创建 POJO 端点:

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

  <servlet>
    <servlet-name>Echo</servlet-name>
    <servlet-class>echo.Echo</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Echo</servlet-name>
    <url-pattern>/Echo</url-pattern>
  </servlet-mapping>
</web-app>
Copy to Clipboard Toggle word wrap

web.xml 和单个 Java 类现在可以用于创建 WAR:

$ mkdir -p WEB-INF/classes
$ cp -rp echo WEB-INF/classes/
$ cp web.xml WEB-INF
$ jar cvf echo.war WEB-INF
added manifest
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/Echo.class(in = 340) (out= 247)(deflated 27%)
adding: WEB-INF/web.xml(in = 576) (out= 271)(deflated 52%)
Copy to Clipboard Toggle word wrap

然后可以将 WAR 部署到 JBoss EAP。这会在内部调用 wsprovide,这将生成 WSDL。如果部署成功,并且您正在使用默认设置,它应在管理控制台中可用。

注意

对于可移植的 Jakarta XML Web 服务部署,可以添加之前生成的打包程序类到部署中。

使用 wssume 的自顶策略

自上而下的开发策略从该服务的抽象合同开始,其中包括 WSDL 文件和零个或多个架构文件。然后,使用 wssume 工具来消耗此合同,生成注解的 Java 类,以及定义它的可选来源。

注意

ws Consume 可能会在 Unix 系统中出现符号链接问题。

使用底部示例中的 WSDL 文件,可以生成遵循此服务的新 Java 实施。k 选项 传递到 ws Consume 以保留 生成的 Java 源文件,而不是仅提供 Java 类:

$ EAP_HOME/bin/wsconsume.sh -k EchoService.wsdl
Copy to Clipboard Toggle word wrap

下表显示了每个生成的文件的用途:

Expand
表 3.2. 生成的文件
File用途

Echo.java

服务端点接口

EchoResponse.java

用于响应消息的 wrapper bean

EchoService.java

仅供 Jakarta XML Web 服务客户端使用

Echo_Type.java

用于请求消息的 wrapper bean

ObjectFactory.java

Jakarta XML Binding XML Registry

package-info.java

Jakarta XML Binding 软件包注解的拥有者

检查服务端点接口发现的注释比底部上例中手动编写的类中更明确,但它们评估到同一合同。

@WebService(targetNamespace = "http://echo/", name = "Echo")
@XmlSeeAlso({ObjectFactory.class})
public interface Echo {

    @WebMethod
    @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
    @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
    @WebResult(name = "return", targetNamespace = "")
    public java.lang.String echo(
        @WebParam(name = "arg0", targetNamespace = "")
        java.lang.String arg0
    );
}
Copy to Clipboard Toggle word wrap

除了打包之外缺少的唯一部分是实施类,现在可以使用上述界面编写。

package echo;

@javax.jws.WebService(endpointInterface="echo.Echo")
public class EchoImpl implements Echo {
   public String echo(String arg0) {
      return arg0;
   }
}
Copy to Clipboard Toggle word wrap

3.1.2. 客户端开发策略

在详细讲解客户端之前,务必要了解 Web 服务的核心分离概念。Web 服务不是最适合内部 RPC 服务,即使这些服务可以以这种方式使用。有更好的技术可以做到这一点,如 CORBA 和 RMI。Web 服务专为可互操作的粗粒度交流而设计。不期望或保证参与 Web 服务交互的各方将位于任何特定的位置,在任何特定的操作系统上运行,或者使用任何特定编程语言编写。因此,明确分隔客户端和服务器实施非常重要。他们唯一应当具有的共性是抽象合同定义。如果出于任何原因,您的软件不遵循此主体,那么您不应使用 Web 服务。由于上述原因,建议使用自上而下的方法开发客户端,即使客户端在同一服务器上运行也是如此。

使用 wssume 的自顶策略

本节重复了服务器端上下一节的流程,但它使用了已部署的 WSDL。这是为 soap :address (如下所示)检索正确的值,该值在部署时计算。如有必要,可在 WSDL 中手动编辑这个值,但您必须小心提供正确的路径。

示例 :已部署 WSDL 中的 soap:address

<wsdl:service name="EchoService">
  <wsdl:port name="EchoPort" binding="tns:EchoServiceSoapBinding">
    <soap:address location="http://localhost.localdomain:8080/echo/Echo"/>
  </wsdl:port>
</wsdl:service>
Copy to Clipboard Toggle word wrap

使用 ws Consume 为部署的 WSDL 生成 Java 类。

$ EAP_HOME/bin/wsconsume.sh -k http://localhost:8080/echo/Echo?wsdl
Copy to Clipboard Toggle word wrap

注意 EchoService.java 类如何存储从中获取 WSDL 的位置。

@WebServiceClient(name = "EchoService",
                  wsdlLocation = "http://localhost:8080/echo/Echo?wsdl",
                  targetNamespace = "http://echo/")
public class EchoService extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://echo/", "EchoService");
    public final static QName EchoPort = new QName("http://echo/", "EchoPort");

    ...

    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort() {
        return super.getPort(EchoPort, Echo.class);
    }

    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort(WebServiceFeature... features) {
        return super.getPort(EchoPort, Echo.class, features);
    }
}
Copy to Clipboard Toggle word wrap

如您所见,此生成的类扩展了 Jakarta XML Web Services javax.xml.ws.Service 中的主要客户端入口点。虽然您可以直接使用 服务,但这要简单得多,因为它能为您提供配置信息。注意 getEchoPort() 方法,它会返回我们服务端点接口的实例。然后,可以通过对返回的接口调用方法来调用任何 Web 服务操作。

重要

不要引用生产应用中的远程 WSDL URL。这会导致每次实例化 Service 对象时网络 I/O。相反,请使用已保存的本地副本上的 工具,或者使用构造器的 URL 版本来提供新的 WSDL 位置。

编写并编译客户端:

import echo.*;

public class EchoClient {

   public static void main(String args[]) {

      if (args.length != 1) {
          System.err.println("usage: EchoClient <message>");
          System.exit(1);
      }

      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
      System.out.println("Server said: " + echo.echo(args0));
   }
}
Copy to Clipboard Toggle word wrap

您可以通过设置 ENDPOINT_ADDRESS_PROPERTY,在运行时更改操作的端点地址,如下所示:

EchoService service = new EchoService();
Echo echo = service.getEchoPort();

/* Set NEW Endpoint Location */
String endpointURL = "http://NEW_ENDPOINT_URL";
BindingProvider bp = (BindingProvider)echo;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);

System.out.println("Server said: " + echo.echo(args0));
Copy to Clipboard Toggle word wrap
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat