内容


用JSR-109构造可互操作的Web服务

理解JSR-109的基本知识

Comments

Web 服务的一个主要目标是达到跨平台和运行时的互操作性。把 Web 服务集成到Java 2 Platform, Enterprise Edition (J2EE)环境是朝这个目标迈进了一大步。JAX-RPC(JSR-101)是朝着这个方向前进的第一步,为了在Java平台开发和部署Web服务定义一个标准的Java APIs集合和一个编程模型。JSR-109构造在JAX-RPC之上。它在J2EE环境里部署Web服务定义了一个标准的机制,更确切地说,是在Enterprise JavaBean (EJB)技术和servlet容器领域定义的。这些规范都要集成到J2EE 1.4规范中。他们作为J2EE的Web服务的基础。

本文描述了JSR-109的优点并举例说明。在你开始之前,你应当有以下几方面的工作知识:

  • WSDL
  • XML
  • Web services
  • JAX-RPC (JSR-101)
  • EJB components

J2EE Web服务开发的角色

J2EE平台在应用程序开发周期中定义了几个角色。它们包括:J2EE产品提供者、应用程序组件提供者、应用程序组装者、部署者、系统管理者和工具提供者。在把Web服务开发集成到J2EE平台的过程中,JSR-109为现存的J2EE平台角色定义了附加的任务。J2EE产品提供者分配到的任务是提供JAX-RPC定义的Web服务的运行时支持、Web服务容器、Web服务的J2EE平台API、JAX-RPC和JSR-109定义的特性、J2EE Web服务的开发工具。在实际的J2EE Web服务开发流程中,开发者、组装者和部署者分配有专门的任务。 图1显示了J2EE Web服务的开发流程。

Web services for J2EE development flow
Web services for J2EE development flow

通常,一个开发者要提供如下一些东西:

  • Web服务定义
  • Web服务的实现
  • Web服务的结构信息
  • 处理器(handler)的实现
  • Java编程语言和WSDL映射
  • 把所有Web服务相关的作品打包放入J2EE模块

图2概述了开发者在服务器和客户端编程模型中的任务。我们将在本文后面为这些编程模型提供更多的细节。 图2也阐明了每个专门的资源所承担的任务。例如,Web服务定义功能是以WSDL文件的形式提供,Web服务的机构信息和Java <=> WSDL映射分别定义在webservices.xml和jaxrpcmapping.xml文件,这两个XML文件是定义在服务器编程模型中的部署描述符。

Role of a developer
Role of a developer

一个组装者得到由开发者开发的J2EE模块,然后将它们组装成为一个完整的J2EE应用程序。一个组装者的职责如下:

  • 将模块组装到Enterprise Application Archive (EAR)中
  • 在应用程序中配置模块,例如分解模块依赖性
  • 配置处理器(handler)

图3概述了一个组装者的任务。

Role of a assembler
Role of a assembler

一个开发者的职责如下:

  • 为EAR中的Web服务器容器解析端点地址
  • 用J2EE Web服务产品提供者提供的部署工具为Web服务产生存根
  • 解析每个用于服务参考的WSDL文档
  • 解析由一个端口组件引用声明的端口访问
  • 部署企业应用程序

图4概述了一个开发者的任务。

Role of a deployer
Role of a deployer

JSR-109的优点

在JSR-109之前,部署一个Web服务的过程是和目标运行时高度耦合的。部署一个Web服务到Apache Axis和部署到 Apache SOAP是完全不同的。各个已经部署了Web服务的机构会要求一些有力论据,来说明为什么他们要转到JSR-109部署模型,放弃以前的投资。JSR-109的目的是促进在J2EE环境中建立可互操作性强并且可移植性好的Web服务。JSR-109利用现有的J2EE技术,为Web服务的部署提供工业标准。它清楚的定义了J2EE Web服务产品提供者必须支持的需求。它允许一个J2EE Web服务能通过基于XML的部署描述符来配置,对Web服务的开发者、组装者和部署者隐藏了系统的复杂性。知道了JSR-109如何工作就使得你可以配置一个J2EE Web服务而不需要学习底层系统的实现细节。最后,一旦Web服务提供者采用JSR-109,那么移植和部署就变成例行公事般简单。

服务器编程模型

服务器编程模型试图标准化J2EE环境中Web服务的部署。更确切的说,它在Web容器中定义了一个基于servlet实现的bean的部署,并在EJB容器中定义了一个无状态会话EJB实现的部署。两种类型的服务实现都使用了Service Endpoint Interface(SEI)——参考JAX-RPC (JSR-101)——来定义Web服务的方法签名。SEI必须遵循Java编程语言和由JAX-RPC定义的WSDL映射规则。服务实现bean必须实现由SEI定义的所有方法。对于EJB服务实现,SEI方法必须是EJB组件远程接口方法的一个子集。服务实现bean的生命周期由和它相关联的容器控制。通常,一个服务实现bean将经历4个阶段:实例化阶段、初始化阶段、执行阶段和删除阶段。容器调用服务实现bean的 newInstance方法创建一个实例,这就开始了它的生命周期。然后容器通过其容器的特定方法初始化该bean。对于一个基于servlet的实现bean,调用 init方法进行初始化。对于一个EJB实现,会调用 setSessionContextejbCreate方法。服务实现bean现在准备处理服务请求。当从容器中删除该bean时,其生命周期终止。对于Web和EJB实现,可分别调用 destroyejbRemove方法。 图5显示了一个基于servlet的实现bean的生命周期, 图6显示了一个会话EJB组件的生命周期。

Lifecycle of a servlet-based implementation bean
Lifecycle of a servlet-based implementation bean
一个会话EJB的生命周期
Lifecycle of a session EJB
Lifecycle of a session EJB

一个服务实现bean不允许携带任何状态,例如容器可能创建和池化bean的多个实例以优化请求处理。

一个Web服务不仅能在J2EE环境中使用,而且可以跨异构平台使用。为了达到这个目的,使用一个WSDL作为Web服务的合约。在一个SEI和一个WSDL之间的映射必须遵循Java编程语言和由JAX-RPC定义的映射规则。这些映射规则超出了本文的范围因此在这儿我们不讨论它们。构造在JAX-RPC之上的JSR-109定义了两个基于XML的部署描述符以在J2EE环境中详细描述Web服务部署特征。这两个部署描述符是webservices.xml和jaxrpcmapping.xml。

webservices.xml文件定义已部署的Web服务的结构信息。在WSDL文件中定义的每个服务被映射到webservices.xml文件中一个相应的Web服务描述。你可以把一个Web服务描述想象成是由一个企业应用程序提供的服务。 图7显示了在WSDL服务和Web服务描述之间的映射的示例。

Mapping between WSDL services and Web services descriptions
Mapping between WSDL services and Web services descriptions

每一个 webservice-description元素必须有一个名字、一个到WSDL文件的引用、一个到JAX-RPC映射文件的引用和一个或多个端口组件。Web服务描述名通过 webservice-description-name元素定义,该元素在文件webservices.xml中必须唯一。 wsdl-file元素和 jaxrpc-mapping-file元素在J2EE模块中定义各自的WSDL文件和JAX-RPC映射文件的位置。在图中显示的Web服务的其他组件是在 wsdl:port元素中定义的端口。一个端口组件定义一个Web服务的服务器视图。它提供Web服务的访问点和实现细节。一个端口组件直接和一个WSDL端口相关。 图8图解了各种关系。

WSDL port to port component relationship
WSDL port to port component relationship

图8中所示,一个端口组件通过 wsdl-port元素引用它相关的WSDL端口。 namespaceURI元素定义WSDL端口的目标名字空间(蓝色箭头), localpart元素定义WSDL端口的本地名字(红色箭头)。除WSDL端口引用之外,每个端口组件有一个到SEI和服务实现bean的引用。 service-endpoint-interface元素定义了SEI的充分合格的类名, service-impl-bean元素定义了Web服务的实现。对于一个基于servlet的实现bean, servlet-link元素被用于引用在Web模块的web.xml文件中定义的Web服务。 图9 显示了webservices.xml和web.xml之间的映射。对于一个ELB实现,一个 ejb-link元素被用于引用在EJB模块的ejb-jar.xml文件中定义的EJB。 图10显示了webservices.xml和ejb-jar.xml之间的映射。

WSDL port to port component relationship
WSDL port to port component relationship
WSDL port to port component relationship
WSDL port to port component relationship

JSR-109也标准化了对JAX-RPC处理器(handler)的支持。处理器类似于在 servlet 2.3规范中定义的servlet过滤器。在servlet编程模型中,一个处理器能在一个请求被分发到一个Web服务终端之前对它进行预处理,并且它能在一个响应发送到客户机前对它进行后置处理。通常,如果使用了SOAP绑定协议的话,一个处理器可以访问和修改SOAP请求报头和内容。然而,一个处理器不能改变请求消息的种类。例如,重定向请求,改变操作名,改变消息部分的数量或修改部分的类型。

既然处理器在一个特定的Web服务终端上操作,它们被声明为端口组件的一部分。在webservices.xml文件中,一个处理器通过 handler元素定义, handler-class元素详细描述处理器的合格的类名。此外,在服务器编程模型中,一个处理器可通过初始化参数、SOAP报头和SOAP角色来进行配置。 图11显示了一个已经配置了处理器的端口组件。

Port component with handlers
Port component with handlers

init-param元素在初始化阶段为处理器提供初始化参数,更准确的说,是当一个容器调用该操作者的init方法时。 soap-header元素定义一个处理器将处理的SOAP报头的合格的名字。名字不在列表上的SOAP报头将被忽略。 soap-role元素包含SOAP角色定义,处理器将扮演其中的一个角色。这就完成了关于在JSR-109中定义的服务器编程模型的讨论。接下来将讨论客户机编程模型。

客户机编程模型

客户机编程模型提供了一个J2EE环境中的Web服务的客户机视图。运行时细节,例如协议绑定和传送对于客户机来说是透明的。客户机以类似于本地方法的某种方式调用Web服务。JSR-109详细描述了调用Web服务的三种机制:

  1. 静态存根
  2. 动态代理
  3. Dynamic Invocation Interface (DII)

静态存根是一个Java类,该类静态地绑定到SEI、WSDL端口和端口组件。它同时也和一个特定的协议绑定和传送联系在一起。一个存根类定义一个SEI定义的所有方法,因此,一个客户机可以通过存根类直接调用Web服务方法。它使用起来非常简单并且不需要配置。然而,存根类主要的不足之处在于即使是对Web服务定义做很小的变动也会造成存根类无法使用,这时存根类必须重建。如果你要为一个非常稳定并且不太可能谋淦涠ㄒ宓牟稺eb服务创建一个客户机时,存根类是非常便利的。

动态代理,正如它的名字暗示的,能在运行时动态的支持一个SEI而不需要产生任何代码实现一个特定的SEI。一个动态代理可以在运行时通过提供一个SEI来获得。一个动态代理在Web服务开发周期中非常有用。一个Web服务的定义,更准确的说,它的SEI在一段时间内可能会被大量的修改。使用一个存根类来测试Web服务可能是非常繁琐的,因为存根类必须在每次对SEI修改后重建。既然这样,动态代理会更适合,因为它只需要每次SEI修改时重新实例化(而不像使用静态存根时重建)就行了。

DII为每一个动态调用定义一个javax.xml.rpc.Call对象示例。不像静态存根和动态代理,一个javax.xml.rpc.Call对象在使用前必须配置。客户机必须提供如下一些东西:

  • 操作名称
  • 参数名称、类型和模式(in、out还是inout)
  • 端口类型和目标服务终端地址
  • 协议和转换属性

这不是很方便,然而,这种方案的主要优点是既然javax.xml.rpc.Call对象不绑定在任何东西上,Web服务定义上的改变对客户机造成的影响将没有其它两种情况大。你可以把DII想象成是类似于Java映像,访问类、方法和域是在运行时动态配置的。

客户机编程模型的风格和服务器编程模型很相像。它使用两个基于XML的部署描述符描述客户机的部署特征。这两个部署描述符是webservicesclient.xml和jaxrpcmapping.xml。每个被客户机引用的Web服务是通过webservicesclient.xml文件中的一个 service-ref元素来表现。每个服务引用都必须有一个名称和一个服务接口。附加的一个或更多端口组件引用提供Web服务的接口,一个指向服务的WSDL文件的 wsdl-file元素,一个指向客户机的Java和WSDL映射文件的 jaxrpc-mapping-file元素,和一个定义特定的被引用的WSDL服务的合格的名字。 图12显示了一个在前面部分中描述的Stock Quote服务的服务引用定义的示例。

Service Reference for the Stock Quote Service
Service Reference for the Stock Quote Service

service-interface元素描述了JAX-RPC Service接口的完全合格的类名, port-component-ref元素定义了SEI。一个服务接口是客户机编程模型中的Web服务的Java表示。该接口必须实现javax.xml.rpc.Service。它能被用来产生一个存根类、动态代理或javax.xml.rpc.Call对象。一个存根类必须实现SEI,因为SEI定义Web服务的签名。 图1314分别显示了Stock Quote服务中的一个Service接口和一个SEI。

Service Interface for the Stock Quote Service
Service Interface for the Stock Quote Service
Service Endpoint Interface for the Stock Quote Service
Service Endpoint Interface for the Stock Quote Service

和服务器编程模型不一样,客户端处理器和服务引用联系在一起,而不是和端口组件引用相关。它们能在一个请求发送到服务端或一个响应返回到客户机存根、代理或javax.xml.rpc.Call对象之前处理它。除了定义在服务器编程模型中的那些处理器有一个或多于一个可配置参数和端口名称之外,客户机处理器和它们的定义方式相同。因为它们和服务引用关联在一起而不是端口组件引用,端口名称可以用来将处理器和WSDL端口关联。通过端口名称,你可以限制当服务终端(WSDL端口)被调用时哪些处理器运行。 图15显示了在Stock Quote服务中描述的登录处理器。既然这样,登录处理器将只在GetQuote端口被调用时运行,而不是Purchase端口。

Handler for the Stock Quote Service
Handler for the Stock Quote Service

JAX-RPC映射

JSR-109难题的最后一部分是标准化Java <=> WSDL映射的机制。JAX-RPC提供这些映射的规则,而JSR-109提供一个基于XML的部署描述符的标准化表示。该部署描述符没有标准的文件名;它的名字由在webservices.xml文件和webservicesclient.xml文件中的 jaxrpc-mapping-file元素来决定。JAX-RPC映射文件的结构和WSDL文件的结构匹配得非常好。在JAX-RPC映射文件中你看到的第一个东西就是Java包和XML名字空间之间的关系。 package-mapping元素为一个J2EE Web服务的实体提供鉴定。 图16显示了这种映射的一个例子。

Java Package to XML Namespace Mapping
Java Package to XML Namespace Mapping

如前节所述,每个由企业应用程序提供的服务在WSDL文件中表现为一个 wsdl:service元素。在JAX-RPC映射文件中,这表现为一个 service-interface-mapping元素。在这个元素中包含的是Sevice接口、WSDL服务名称和WSDL端口名称的合格类名的映射。Service接口是Web服务的Java表示法,它必须实现javax.xml.rpc.Service接口。 图17显示了这些映射关系。

WSDL Service to Service Interface Mapping
WSDL Service to Service Interface Mapping

除了WSDL服务和WSDL端口映射之外,JAX-RPC映射文件也为WSDL绑定、WSDL端口类型、WSDL消息和WSDL各部分提供映射。它们被映射到 service-endpoint-interface-mapping元素。如 图18所示, service-endpoint-interface-mapping元素也定义SEI的完全合格的类名。在此,它是sample.GetQuotePortType。

WSDL Port Type to Service Endpoint Interface Mapping
WSDL Port Type to Service Endpoint Interface Mapping

JAX-RPC映射文件中最有意思的成分是Java <=> XML类型映射。JSR-109为JAX-RPC映射文件中的XML模式类型定义和元素声明定义了一个标准表示法。它们都被映射到 java-xml-type-mapping元素。 java-xml-type-mapping元素包含四个至关紧要的消息,它们是:

  1. class-type元素中定义的XML Schema类型的JavaBean组件表现的合格类名。
  2. root-type-qname元素中定义的充分合格的XML Schema类型。
  3. qname-scope元素中定义的XML Schema类型的范围。可能值为simpleType、complexType和element。
  4. Java数据成员或JavaBean组件属性和XML Schema元素之间的关系。 variable-mapping元素定义了这种关系。

图19显示了这种映射的一个详细的示例。

XML Schema Type to Java XML Type Mapping
XML Schema Type to Java XML Type Mapping

Stock Quote示例中的WSDL文件、服务器部署描述符(webservices.xml)、客户机部署描述符(webservicesclient.xml)和JAX-RPC映射文件贯穿本文始终,可以在本文的 资源部分找到它们。

改进之处

JSR-109为在J2EE环境中部署Web服务提供了一个初步的标准化机制。但是还存在很多改进的地方,特别是在安全领域。虽然对安全的Web服务的需求和拥有可互操作的Web服务一样重要,在标准化跨平台的安全模型上仍存在挑战。就拿JSR-109来说,它定义了它试图解决的安全需求,但是现在的标准化得遵从该规范的未来版本。安全需求包括以下内容:

  • 基于凭证的授权。例如HTTP BASIC-AUTH。
  • 由企业安全模型定义的授权。
  • 使用XML编码和XML保证完整性和机密性。
  • 数字签名。
  • 审计。
  • 无抵赖。

除了在安全性上改进之外,在与JAX-RPC相关的方面JSR-109还存在改进的地方。例如,JAX-RPC定义了一个彻底的Java <=> XML序列化和反序列化框架,然而JSR-109没有提供任何对该领域的支持。另外,JSR-109没有为由JAX-RPC定义的映射规则提供完全的表示。它缺乏对MIME类型的支持。例如,JAX-RPC允许java.lang.String映射到MIME类型:text/plain,然而JSR-109不能支持这种映射,因为没有为JAX-RPC映射文件中的MIME类型提供标准的表示法。

希望这些问题会在JSR-109未来的规范中解决。为构造Web服务提供一个更集成化的、互操作性更强和可移植性更好的体系结构。

总结

本文讨论了JSR-109如何标准化J2EE环境下的Web服务和Web服务客户机的部署。本文提供了代码示例讲解如何进行服务器和客户机编程。将JAX-RPC和JSR-109集成到J2EE 1.4规规范中去将是下一个里程碑,那时将讨论如何在J2EE环境中构造互操作性更强和可移植性更好的Web服务。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=21338
ArticleTitle=用JSR-109构造可互操作的Web服务
publish-date=08012003