JAX-RPC与JAX-WS:动态调用接口

日期: 2008-06-17 作者:Russell ButekNick Gallardo 来源:TechTarget中国

  本系列文章讨论 Java? API for XML-based RPC (JAX-RPC) 1.1 和 Java API for XML Web Services (JAX-WS) 2.0,本文是其中的第 4 部分,将对动态调用模型进行比较。本文将给出每个模型的示例,以介绍其相似处和主要差异。


  引言


  JAX-RPC 1.1 和 JAX-WS 2.0 客户机动态模型都提供一组类似的抽象步骤来进行调用。


  定义服务。
  从此服务创建动态调用对象。
  构建消息。
  调用操作。


  尽管这两个模型都采用相同的步骤,不过本文将说明两个模型间细节的差异。我们将使用前一篇文章中所用的 HelloWorld Web 服务描述语言(Web Services Description Language,WSDL)。具体如清单 1 中所示。


  清单 1. HelloWorld 服务的 WSDL
                <?xml version=”1.0″ encoding=”UTF-8″?>
        <wsdl:definitions   http://schemas.xmlsoap.org/wsdl/soap/”>http://schemas.xmlsoap.org/wsdl/soap/“
       
        http://schemas.xmlsoap.org/wsdl/”>http://schemas.xmlsoap.org/wsdl/“
        http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema” name=”HelloWorld”
        targetNamespace=”urn:helloWorld/sample/ibm/com”>
    <wsdl:types>
      <xsd:schema targetNamespace=”urn:helloWorld/sample/ibm/com”
         
          http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“>
        <xsd:element name=”hello”>
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name=”name” nillable=”true” type=”xsd:string” />
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
        <xsd:element name=”helloResponse”>
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name=”response” nillable=”true” type=”xsd:string” />
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:schema>
    </wsdl:types>
    <wsdl:message name=”helloRequestMsg”>
      <wsdl:part element=”tns:hello” name=”helloParameters” />
    </wsdl:message>
    <wsdl:message name=”helloResponseMsg”>
      <wsdl:part element=”tns:helloResponse” name=”helloResult” />
    </wsdl:message>
    <wsdl:portType name=”HelloWorld”>
      <wsdl:operation name=”hello”>
        <wsdl:input message=”tns:helloRequestMsg” name=”helloRequest” />
        <wsdl:output message=”tns:helloResponseMsg” name=”helloResponse” />
      </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name=”HelloWorldBinding” type=”tns:HelloWorld”>
      <soap:binding style=”document” transport=”http://schemas.xmlsoap.org/soap/http” />
      <wsdl:operation name=”hello”>
        <soap:operation soapAction=”urn:helloWorld/sample/ibm/com/hello” />
        <wsdl:input name=”helloRequest”>
          <soap:body use=”literal” />
        </wsdl:input>
        <wsdl:output name=”helloResponse”>
          <soap:body use=”literal” />
        </wsdl:output>
      </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name=”HelloWorldService”>
      <wsdl:port name=”port” binding=”tns:HelloWorldBinding”>
        <soap:address location=”http://tempuri.org/” />
      </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>


  JAX-RPC 的动态调用接口


  JAX-RPC 的动态调用接口(Dynamic Invocation Interface,DII)是 Call 对象 (javax.xml.rpc.Call)。清单 2 中给出了使用 Call 对象调用清单 1 的 HelloWorld 服务的完整客户机主类。还可以在清单 2 的介绍中看到对抽象步骤进行了说明。


  清单 2. JAX-RPC 的 DII 客户机
                package com.ibm.samples.dii;


  import javax.xml.namespace.QName;
  import javax.xml.rpc.Call;
  import javax.xml.rpc.ParameterMode;
  import javax.xml.rpc.Service;
  import javax.xml.rpc.ServiceFactory;
  import javax.xml.rpc.encoding.XMLType;


  public class HelloWorldClient {


      public static void main(String[] args) {
          try {
            // Define the service.
            QName serviceName = new QName(
                    “urn:helloWorld/sample/ibm/com”,
                    “HelloWorldService”);
            ServiceFactory factory = ServiceFactory.newInstance();
            Service service = factory.createService(serviceName);


            // create the dynamic invocation object from this service.
            Call call = service.createCall();
            call.setTargetEndpointAddress(
                    “http://localhost:9081/HelloWorldService/services/port”);


            // Build the message.
            QName operationName = new QName(
                    “urn:helloWorld/sample/ibm/com”,
                    “hello”);
            call.setOperationName(operationName);
            call.addParameter(
                    “name”,             // parameter name
                    XMLType.XSD_STRING, // parameter XML type QName
                    String.class,       // parameter Java type class
                    ParameterMode.IN);  // parameter mode
            call.setReturnType(XMLType.XSD_STRING);
            call.setProperty(
                    Call.OPERATION_STYLE_PROPERTY,
                    “wrapped”);


            // Invoke the operation.
            Object[] actualArgs = {“Georgia”};
            String response = (String) call.invoke(actualArgs);
            System.out.println(“response = ” + response);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
    }


  下面让我们了解一下这些抽象步骤的细节:


  定义服务。通过使用 WSDL 的服务完全限定名称构造 javax.xml.rpc.Service 对象。


  从此服务创建动态调用对象。在 JAX-RPC 中,动态调用对象为 javax.xml.rpc.Call。


  构建消息。在此步骤中,将使用关于操作的信息填充 Call 对象。此处需要提出的一点是:我们将调用 call.setProperty(Call.OPERATION_STYLE_PROPERTY, “wrapped”);。wrapped 不是 JAX-RPC 为此属性定义的值。JAX-RPC 仅定义 rpc 和 document。不过,rpc 实际上表示 RPC/Encoded,而 document 实际表示 Document/Literal, Non-Wrapped。自从 JAX-RPC 推出后,Document/Literal Wrapped 模式就成为了行业标准,因此其 Call 对象并不能很好地对其进行处理。可以完成此工作,但效果不太好。对此属性进行扩展,以包括 wrapped 值,这是 IBM 填补此规范空白的方法,但并非标准扩展。


  调用操作。此示例中的输入是一个简单的字符串,因此将使用字符串填充参数,并将其传递给调用函数。响应也是字符串,在此示例中将直接对其进行显示。
JAX-WS 的动态 Dispatch 接口


  JAX-WS 的 DII 是 Dispatch 对象 (javax.xml.ws.Dispatch)。清单 3 中给出了通过 Dispatch 对象调用清单 1 的 HelloWorld 服务的完整客户机主类。可以在清单 3 的介绍中看到对抽象步骤进行了说明。


  清单 3. JAX-WS 的 DII 客户机
                import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import javax.xml.namespace.QName;
  import javax.xml.transform.Source;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.stream.StreamResult;
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.ws.Dispatch;
  import javax.xml.ws.Service;
  import javax.xml.ws.soap.SOAPBinding;


  public class HelloWorldClient {


      public static void main(String[] args) {
        try {     
            // Define the service.
            QName svcQname = new QName(
                    “urn:helloWorld/sample/ibm/com”,
                    “HelloWorldService”);
            QName portQName = new QName(
                    “urn:helloWorld/sample/ibm/com”,
                    “port”);
            Service svc = Service.create(svcQname);
            svc.addPort(
                    portQName,
                    SOAPBinding.SOAP11HTTP_BINDING,
                    “http://localhost:9080/JAXBSampleWebService/HelloWorldService”);


            // create the dynamic invocation object from this service.
            Dispatch<Source> dispatch = svc.createDispatch(
                    portQName,
                    Source.class,
                    Service.Mode.PAYLOAD);


            // Build the message.
            String content =
                    “<ns2:hello xmlns_ns2=”urn:helloWorld/sample/ibm/com”>” +
                      “<name>Georgie</name>” +
                    “</ns2:hello>”;
            ByteArrayInputStream bais = new ByteArrayInputStream(content.getBytes());
            Source input = new StreamSource(bais);


            // Invoke the operation.
            Source output = dispatch.invoke(input);


            // Process the response.
            StreamResult result = new StreamResult(new ByteArrayOutputStream());
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(response, result);
            ByteArrayOutputStream baos = (ByteArrayOutputStream) result.getOutputStream();


            // Write out the response content.
            String responseContent = new String(baos.toByteArray());
            System.out.println(responseContent);
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}


  接下来让我们看看此 JAX-WS 动态客户机中的这些抽象步骤的细节:


  定义服务。与 JAX-RPC 模型中类似,将基于完全限定名称定义服务,但还要定义该服务的端口。


  从此服务创建动态调用对象。在 JAX-WS 中,动态调用对象为 javax.xml.ws.Dispatch。这个类利用了 Java 5 中的新泛型功能支持多参数类型。


  构建消息。在此处构建原始 SOAP 消息主题内容。


  调用操作。您将 SOAP 主题的内容发送到服务,并从服务接收 SOAP 响应。


  模型间的差异


  从抽象步骤来看,JAX-RPC 和 JAX-WS 的动态调用模型非常相似。但事实并非如此。看看每个示例的细节,就会发现这些模型实际上有很大的区别。接下来让我们更为深入地分析一下其中的一些差异。


  操作样式


  相当清楚的是,两个模型之间的主要差异在于,JAX-RPC 采用远程过程调用(Remote Procedure Call,RPC)模型(即规范名称中的 RPC),而 JAX-WS 的动态客户机采用消息传递模型。对于 JAX-RPC,必须配置 Call 对象来显式地从 WSDL 调用特定操作。在 JAX-WS 中,Dispatch 对象不知道所调用的是哪个操作,仅仅负责发送 XML 数据而已。


  参数样式


  对于 JAX-RPC,所传递的参数类型保留规范定义的 XML 模式到 Java 的映射。对于 JAX-WS,可以采用两种不同的方式使用 Dispatch 对象:作为基于 XML 的 Dispatch(如本文中所示)或作为基于 JAXB 的 Dispatch。基于 XML 的 Dispatch 接受基于以下对象类型的参数:javax.xml.transform.Source、javax.xml.soap.SOAPMessage 和 javax.activation.DataSource。基于 JAXB 的 Dispatch 要求用户配置可用于封送和取消封送参数实例(JAXB Java Bean)的 javax.xml.bind.JAXBContext。


  参数样式之间的另一个主要差异在于所传递的内容。对于 JAX-RPC,参数始终作为请求的参数数据使用。而对于 JAX-WS,有两种不同的参数模式:有效负载 (PAYLOAD) 和消息 (MESSAGE) 模式。PAYLOAD 模式表示参数仅仅代表 SOAP 主体的内容,而 MESSAGE 模式表示参数代表整个消息,包括 SOAP 信封。


  调用模式


  如上所述,JAX-RPC 和 JAX-WS 都通过 invoke() 方法提供了同步双向调用。这两个模型都提供了用于通过 invokeOneWay 方法调用单向 Web 服务操作的方法。两个模型之间的主要差异在于,JAX-WS 还提供异步调用模型。其中包含异步回调模型和异步轮询模型。JAX-RPC 并不提供异步调用选项。


  服务器端动态编程模型


  此处将不会详细讨论的另一个主要差异是,JAX-WS 添加了 JAX-RPC 永远不会有的内容——动态服务器端编程模型。与客户端模型类似,也可以将其配置为使用 PAYLOAD 或 MESSAGE 模式。


  总结


  JAX-RPC 和 JAX-WS 都提供了动态客户机模型。简单而言,可以将二者视为对等。但仔细分析其细节,可以发现 JAX-RPC 的动态模型是 RPC 模型,而 JAX-WS 的动态模型为消息传递模型。JAX-WS API 可提供更大的灵活性,是 Web 服务编程模型发展的下一步目标。JAX-WS 还提供了异步支持和动态服务支持,而 JAX-RPC 并未对此进行定义。


  作者简介


  Russell Butek 是 IBM 的一名 SOA 和 Web 服务顾问。他曾是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request (JSR) 专家组的成员。他参与了 Apache 的 AXIS SOAP 引擎的实现,并推动 AXIS 1.0 遵守 JAX-RPC。
 
  Nick Gallardo 担任 IBM WebSphere 平台软件工程师,主要负责 Web 服务支持的各个方面。在此之前,他从事 IBM WebSphere 和 Tivoli 平台中其他方面的工作。Nick 于 2001 加入 IBM,此前他曾在德克萨斯州奥斯汀市两家不同的初创技术型公司从事开发工作。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐

  • 调用远程CORBA方法参数限制

    我正在写一个Java DII的客户,其内容的资料,接口库。我必须执行一个远程方法有一个参数的类型是一个用户定义的数据类型。如何建立援引的运作,并宣读结果的要求……

  • JAX-WS 2.0规范(二)

    本篇介绍关于JAX-WS 2.0 概要中的其他说明。JAX-WS 2.0也将提出关于实现和使用JAX-RPC 1.0发生的问题:Inclusion in J2SE JAX-WS 2.0准备将JAX-WS……

  • JAX-RPC与JAX-WS:附件文件比较

    本文是本系列的第5部分,将通过分析Web服务描述语言(Web Services Description Language,WSDL)和映射Java接口示例对这两个附件模型进行比较……

  • JAX-RPC与JAX-WS:服务端点接口

    从整体上看,Java API for XML-based RPC(JAX-RPC) 1.1服务端点接口(SEI)和Java API for XML Web Services(JAX-WS)2.0 SEI是非常相似……