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,本文是其中的第 3 部分,比较了从 Web 服务描述语言 (WSDL) 到服务端点接口 (SEI) 的映射。SEI 的概念是在 JAX-RPC 1.0 中首次引入的,在 JAX-WS 2.0 中保留了这个概念,并且添加了一些新的内容。本文将向您介绍其中的主要区别。


  引言


  从整体上看,Java API for XML-based RPC (JAX-RPC) 1.1 服务端点接口 (SEI) 和 Java API for XML Web Services (JAX-WS) 2.0 SEI 是非常相似的。本文将着重介绍它们之间的区别。尽管在结构上存在一定的区别,然而,提供反映 Web 服务契约的接口的目标是相同的。


  比较 SEI 映射


  清单 1 显示了一个简单的 HelloWorld Web 服务所使用的 WSDL。


  清单 1. HelloWorld WSDL
               
   
        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”>
   
               
          http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“>
       
         
           
             
           

         

       

       
         
           
             
           

         

       

     

   

   
     
   

   
     
   

   
     
       
       
     

   

   
      http://schemas.xmlsoap.org/soap/http” />
     
       
       
         
       

       
         
       

     

   

   
     
        http://tempuri.org/” />
     

   

  


  清单 2 显示了这个 WSDL 中 Java SEI 的 JAX-RPC 映射,其中不包含方法签名(稍后您将看到有关这些内容的细节)。


  清单 2. JAX-RPC HelloWorld SEI
               
  package com.ibm.samples;
  public interface HelloWorld extends java.rmi.Remote {
  …
  }


  清单 3 显示了用于相同的 WSDL 的 JAX-WS SEI。


  清单 3. JAX-WS HelloWorld SEI
               
  package com.ibm.samples.helloworld;


  import javax.jws.WebService;


  @WebService(name = “HelloWorld”, targetNamespace =   ”urn:samples.ibm.com/HelloWorld”)
  public interface HelloWorld {
    …
  }
  
  其中存在三处区别:


  包:目标命名空间是“urn:helloWorld/sample/ibm/com”。这两个映射都使用了类似域名的字符串,并且颠倒了其中元素的顺序。JAX-RPC 的映射在第一个斜杠处结束。JAX-WS 的映射则继续该字符串,在第一个斜杠后面继续添加信息。这两种规范都允许从自定义的命名空间到包的映射。
 
  注释:JAX-WS 要求所有 SEI 必须包括 @WebService 注释。正如本系列文章的第 1 部分中所介绍的,JAX-WS 支持 JSR-181 Web 服务元数据中定义的各种注释。


  java.rmi.Remote:JAX-RPC SEI 扩展了 java.rmi.Remote 接口。而 JAX-WS 不需要这样做。


  在继续学习操作映射的详细内容之前,关于 SEI 本身还有一处需要说明的地方。尽管 JAX-WS 提供对具有 SEI 的 Web 服务的支持,但是对于所有的服务来说,这并不是强制的。使用 JAX-WS,JavaBean 可以作为 Web 服务实现而自行部署,不需要像 JAX-RPC 那样要求 Bean 必须包括 SEI。所部署的没有 SEI 的 JAX-WS 服务将被认为具有隐式的 SEI。


  比较操作映射


  现在您已经看到了这些接口,下面再对各种操作的映射进行比较。可以使用不同的方法来设计表示具有类似语义的 Web 服务的 WSDL 文档。文章 Which style of WSDL should I use? 提供了关于各种不同风格的 WSDL 文档的概述,以及如何确定哪一种风格更适合您。


  现在,让我们来研究 JAX-RPC 和 JAX-WS 如何映射到每种 WSDL 风格。


  研究 document/literal 包装模式


  清单 1 中的 WSDL 使用了 document/literal 包装模式进行格式化。清单 4 和 5 是 JAX-RPC 和 JAX-WS 中对相同的包装操作的映射。请注意,JAX-WS 向方法中添加了 @RequestWrapper 和 @ResponseWrapper 注释。这些注释为用作操作包装器的元素和为这些包装器元素生成的任何 Java Bean 提供了附加的元数据。这些注释都是可选的。


  清单 4. JAX-RPC 完整的 HelloWorld SEI
               
  package com.ibm.samples;


  public interface HelloWorld extends java.rmi.Remote {
    public java.lang.String hello(java.lang.String name) throws   java.rmi.RemoteException;
  }


  清单 5. JAX-WS 完整的 HelloWorld SEI
               
  package com.ibm.samples.helloworld;


  import javax.jws.WebMethod;
  import javax.jws.WebParam;
  import javax.jws.WebResult;
  import javax.jws.WebService;
  import javax.xml.ws.RequestWrapper;
  import javax.xml.ws.ResponseWrapper;


  @WebService(name = “HelloWorld”, targetNamespace =   ”urn:samples.ibm.com/HelloWorld”)
  public interface HelloWorld {


    @WebMethod(action = “urn:samples.ibm.com/HelloWorld/hello”)
    @WebResult(name = “response”, targetNamespace = “”)
    @RequestWrapper(localName = “hello”,
        targetNamespace = “urn:samples.ibm.com/HelloWorld”,
        className = “com.ibm.samples.helloworld.Hello”)
    @ResponseWrapper(localName = “helloResponse”,
        targetNamespace = “urn:samples.ibm.com/HelloWorld”,
        className = “com.ibm.samples.helloworld.HelloResponse”)
    public String hello(
        @WebParam(name = “name”, targetNamespace = “”)
        String name);
  }


  正如您所看到的,JAX-WS 映射包含大量的注释,但是当您仔细研究根签名时会发现,唯一的区别是JAX-RPC 方法可以引发 java.rmi.RemoteException,而 JAX-WS 方法则不行。


  研究 document/literal 模式


  JAX-RPC 和 JAX-WS 都支持 document/literal 映射操作,但不支持包装映射操作。要在 HelloWorld 示例中实现这一点,您需要删除表示操作名的包装器元素。清单 6 显示了这个 WSDL 文档中相关的部分,并与清单 1 中的 WSDL 进行对比。


  清单 6. 文档/文本 WSDL
               
  
        
     http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“>
       
       
   

  


  
   
  


  
   
  

 
  现在,让我们来研究用于这个新的 WSDL 的 Java 映射。清单 7 和 8 分别显示了 JAX-RPC 和 JAX-WS 映射。JAX-RPC 映射是非常类似的!唯一的区别是参数名称。与前面的情况一样,如果不考虑注释,JAX-RPC 映射和 JAX-WS 映射之间没有什么本质的区别。


  清单 7. JAX-RPC 文档/文本映射
               
  public interface HelloWorld extends java.rmi.Remote {
      public java.lang.String hello(java.lang.String helloParameters)
          throws java.rmi.RemoteException;
  }


  清单 8. JAX-WS 文档/文本映射
               
  @WebService(name = “HelloWorld”, targetNamespace =   ”urn:helloWorld/sample/ibm/com”)
  @SOAPBinding(parameterStyle = ParameterStyle.BARE)
  public interface HelloWorld {


      @WebMethod(action = “urn:helloWorld/sample/ibm/com/hello”)
      @WebResult(name = “helloResponse”,
        targetNamespace = “urn:helloWorld/sample/ibm/com”,
        partName = “helloResult”)
      public String hello(
          @WebParam(name = “hello”,
            targetNamespace = “urn:helloWorld/sample/ibm/com”,
            partName = “helloParameters”)
        String helloParameters);


  }


  请注意,对于 JAX-WS,没有 @RequestWrapper 和 @ResponseWrapper 注释。另外请注意,在接口级别上还出现了一个新的注释,@SOAPBinding。这个注释提供了关于参数风格的信息。如果没有这个注释,parameterStyle 属性的缺省值为 wrapped,应该与清单 1 中的 WSDL 类似。


  研究 RPC/literal 模式


  下面的示例与前两个示例有一些不同。对于 RPC/literal 风格的 WSDL,这些部分定义为类型而不是元素。清单 9 包含了相关的 WSDL 差别。


  清单 9. RPC/文本 WSDL 更改
               
  


  
   
  


  
   
  

 
  清单 10 和 11 中的 Java 映射反映了对 WSDL 的更改。同样地,当去掉注释后,可以得到完全相同的映射。


  清单 10. JAX-RPC RPC/文本映射
               
  public interface HelloWorld extends java.rmi.Remote {
      public java.lang.String hello(java.lang.String helloParameters)
          throws java.rmi.RemoteException;
  }


  清单 11. JAX-WS RPC/文本映射
               
  @WebService(name = “HelloWorld”, targetNamespace =   ”urn:helloWorld/sample/ibm/com”)
  @SOAPBinding(style = Style.RPC)
  public interface HelloWorld {


      @WebMethod(action = “urn:helloWorld/sample/ibm/com/hello”)
      @WebResult(name = “helloResult”, partName = “helloResult”)
      public String hello(
          @WebParam(name = “helloParameters”, partName = “helloParameters”)
          String helloParameters);


  }


  将这个 JAX-WS 接口与前面的进行比较,您将看到保留了 @SOAPBinding 注释,但是现在它不是表示参数风格,而是表示 WSDL 风格。


  研究 RPC/encoded 模式


  对于 RPC/encoded 风格的操作,无法进行比较。JAX-WS 不支持包含编码的 数据表示的 WSDL 文档的任何映射。这是因为 JAX-WS 与 WS-I 的 Basic Profile 1.1 的兼容性原因,其中不允许使用编码的 WSDL 文档。有时候的确需要构建 RPC/encoded Web 服务,在这种情况下您应该坚持使用 JAX-RPC 映射,但是如果您希望编写可互操作的 Web 服务,那么您就不应该使用 RPC/encoded 模式。


  考虑其他的一些区别


  JAX-WS 与 JAX-RPC 在操作映射方面的主要区别是前者引入了异步操作。任何具有双向消息流的 WSDL 操作,或者其中的客户端期待着接收响应的操作,都可以映射为异步的 Java 表示形式。有两种不同的机制,带回调的异步方式和异步轮询,它们需要两种不同的映射。后续的文章将描述这两种类型的操作是如何工作的。本文只是向您介绍一个示例。清单 12 包含一个异步回调操作,其中 javax.xml.ws.AsyncHandler 对象为回调对象。清单 13 包含了一个异步轮询操作映射。


  清单 12. JAX-WS 异步回调
               
  @WebMethod(action = “urn:samples.ibm.com/HelloWorld/hello”)
  @RequestWrapper(localName = “hello”,
      targetNamespace = “urn:samples.ibm.com/HelloWorld”,
      className = “com.ibm.samples.helloworld.Hello”)
  @ResponseWrapper(localName = “helloResponse”,
      targetNamespace = “urn:samples.ibm.com/HelloWorld”,
      className = “com.ibm.samples.helloworld.HelloResponse”)
public Future helloAsync(
      @WebParam(name = “name”, targetNamespace = “”)
      String name,
      @WebParam(name = “asyncHandler”, targetNamespace = “”)
      AsyncHandler asyncHandler);
 
  清单 13. JAX-WS 异步轮询
               
  @WebMethod(action = “urn:samples.ibm.com/HelloWorld/hello”)
  @RequestWrapper(localName = “hello”,
      targetNamespace = “urn:samples.ibm.com/HelloWorld”,
      className = “com.ibm.samples.helloworld.Hello”)
@ResponseWrapper(localName = “helloResponse”,
      targetNamespace = “urn:samples.ibm.com/HelloWorld”,
      className = “com.ibm.samples.helloworld.HelloResponse”)
public Response helloAsync(
      @WebParam(name = “name”, targetNamespace = “”)
      String name);
 
  在 JAX-RPC 中,没有用于 WSDL 操作的异步映射,所以这里没有办法进行比较。然而,重要的是,异步映射仅适用于客户端。对于服务端点,不存在类似的异步映射,只能用于客户端。


  比较 IN/OUT 参数


  JAX-RPC 和 JAX-WS 都支持称为 IN/OUT 参数的参数。在清单 14 中,您可以看到在清单 1 的 WSDL 中添加了一个 IN/OUT 参数。请注意,不管对于输入还是输出,都出现了名为“inout”的参数。在这个场景中,JAX-RPC 和 JAX-WS 将该参数映射为一个 Holder 参数,但是对于不同的映射,其效果是不同的。


  清单 14. 带 IN/OUT 参数的 WSDL
               
  
   
     
       
       
     

   

  


  
   
     
       
       
     

   

  

 
  清单 15 提供了 Holder 参数的 JAX-RPC 映射,而清单 16 提供了 JAX-WS 映射。
 
  清单 15. 带 IN/OUT 参数的 JAX-RPC SEI
               
  public interface HelloWorld extends java.rmi.Remote {
      public java.lang.String hello(
          java.lang.String name,
          javax.xml.rpc.holders.StringHolder inout) throws   java.rmi.RemoteException;
  }


  清单 16. 带 IN/OUT 参数的 JAX-WS SEI
               
  @WebService(name = “HelloWorld”, targetNamespace =   ”urn:helloWorld/sample/ibm/com”)
  public interface HelloWorld {


      @WebMethod(action = “urn:helloWorld/sample/ibm/com/hello”)
      @RequestWrapper(localName = “hello”,
          targetNamespace = “urn:helloWorld/sample/ibm/com”,
          className = “helloworld.sample.ibm.com.Hello”)
      @ResponseWrapper(localName = “helloResponse”,
          targetNamespace = “urn:helloWorld/sample/ibm/com”,
          className = “helloworld.sample.ibm.com.HelloResponse”)
      public void hello(
          @WebParam(name = “name”, targetNamespace = “”)
          String name,
          @WebParam(name = “inout”, targetNamespace = “”, mode = Mode.INOUT)
          Holder inout,
          @WebParam(name = “response”, targetNamespace = “”, mode = Mode.OUT)
          Holder response);


  }


  对于 JAX-RPC,规范中为各种已知的类型定义了一组类作为 Holder 类。这些类型包括 java.lang.String 和其他基本数据类型。对于用户定义的类型,JAX-RPC 需要生成能够处理用户定义类型的自定义的 Holder 类。另一方面,对于 JAX-WS,可以使用 Java 5 的泛型编程特性,提供适用于所有类型(包括用户定义类型)的单个类。


  另一个有趣的内容是返回类型的区别。JAX-WS 并不像 JAX-RPC 那样保存返回类型,而是让方法的返回类型为 void,并使用 Holder 来获取返回值。根据 JAX-WS 中的规则,如果对于一个操作存在多个可以作为 OUT 参数的参数,那么返回类型必须为 void,并且将所有的 OUT 参数映射为 Holder 类型。


  总结


  上面的示例说明,尽管 JAX-RPC 和 JAX-WS 之间存在很多的区别,但是从 WSDL 到服务端点接口结构的映射是非常类似的。关键的区别包括:


  包名不同。


  JAX-RPC 需要 java.rmi.Remote 和 java.rmi.RemoteException,而 JAX-WS 不需要。


  对 Holder 进行了不同的定义。


  即使存在这些类似的地方,但是有一个主要的区别,使得 JAX-WS SEI 不同于 JAX-RPC。JSR-181 注释的使用,使得 JAX-WS SEI 可以以 Java 为中心或者以 WSDL 为中心来表示 Web 服务。可以包括大量的注释,以便将 Java 信息映射回 WSDL 构件。JAX-RPC SEI 无法通过任何形式来提供这类信息。还有一些特性是 JAX-WS 所特有的,即异步调用模型,以及它不需要提前生成 SEI。另一方面,JAX-RPC 也具备一些 JAX-WS 所没有的特性:它支持 RPC/encoded WSDL。


  作者简介


  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中国

相关推荐

  • 当业务流程遭遇软件服务

    要是驾校的教练去出演像《速度与激情》这样的动作电影,我敢打赌他们给人的印象肯定有所不同。有人说:“他们应该更快绑好安全带。”这种分离类似于当今的业务流程管理。

  • 理解并使用IMS SOAP Web服务

    让我们从Web服务的角度来审视这一话题。为了通过简单对象访问协议(SOAP)支持Web服务,IMS需要三大部分的东西。首先是Rational Developer for System z……

  • 用WebSphere DataPower SOA Appliances重写SOAPAction报头

    IBM WebSphere DataPower通常被用于将一个SOAP/HTTP后端Web服务转换或调整为不同的Web服务接口。在这些情况中,几乎都使用中间逻辑来转换SOAP消息。

  • 如何在SOAP应用程序中使用WSDL?

    在过去的几年中,出现了一些标准协议,它们提供了XML中间件的一个重要组成部分:网络化服务的要求。这些网络化服务要求是通过网络。