UML软件工程组织

 

 

使用J2EE 构建服务

2008-07-03 作者:Debu Panda 翻译:magic003 出处:onjava

 

如今,web services 是一门流行的实现面向服务应用的技术。J2EE已经成为一个流行的用来部署web services 应用的平台。并且,J2EE1.4制定了在Java平台上建立和部署web services应用的标准。

在我的上一篇文章中,我从一个Java开发者的角度介绍了面向服务架构。在这篇文章中,我将说明如何在实现了J2EE1.4规范的应用服务器之间,比如Oracle Application Server 10g,使用J2EE1.4建立可互操作的,轻便灵活的服务。

Web Services 架构

在深入研究J2EE平台上web services的开发和部署的细节之前,让我们先简要的查看一下web service的架构。

Web services 有很多种定义,但是简而言之,web services 是能够通过网络被发布,发现和调用的独立的,自我描述的组件。如图1所示,一个web service可能会执行一个简单的功能,比如核算银行存款记录,也可能会是一个横跨多个商业过程的复杂的任务。

image

图1. 一个web service 是如何工作的

有两种与web services 交互的方法:RPC类型和文档类型。最初,RPC类型的web services在工业界很流行,但是最近几年它已经被文档类型的web services所超越,后者被认为是在web services中交换信息的首选方法。

RPC类型的web services提出将数据交换模拟成远程过程调用(RPC)。这在商业应用中是很常见的。对于远程调用和其返回值,让相互交换的消息都遵照一个明确定义的准则。与之相反,文档类型的web services模拟XML文档的交换,交换模式由发送和接收应用程序共同定义。文档类型的服务更能适应需要交换商业或其他类型文档的应用程序,而且不同于RPC类型的web services,发送方不需要期望或等待一个即时的响应。

大多数开发者一定会同意:web services是一种有效的实现SOA的技术,因为它提供了不同平台之间的互操作性,以及依赖于XML,SOAP和HTTP等的轻量级的技术。

平台独立性和技术实现性是web services普及的主要原因。客户端不必了解相关技术的实现,而只需简单地通过网络调用服务就可以了。例如,即使你使用Java/J2EE 技术创建了一个服务并且部署在一个J2EE服务器上,比如Oracle Application Server Container for J2EE(OC4J),客户端也可以使用微软的.NET架构创建。

既然我们已经对web services有了基本的了解,就让我们关注一下构成web service的基本元素吧。

Web Services是由什么构成的?

Web Services 定义语言(WSDL;发音为“wizdle”)文档是一个web service的核心。WSDL描述了服务,而且也是web service保证遵守的“契约”。WSDL提供了对于一个web service的完整的描述,包括端口,操作和相关的消息类型。

这里是WSDL文档的一个简单的例子,它描述了一个Hello World web service:

<definitions 
 name="HelloService" 
 targetNamespace="http://oracle.j2ee.ws/ejb/Hello"
 xmlns="http://schemas.xmlsoap.org/wsdl/" 
 xmlns:tns="http://oracle.j2ee.ws/ejb/Hello" 
 xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
 xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
 xmlns:ns1="http://oracle.j2ee.ws/ejb/Hello/types" 
 xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> 
 <types> 
  <schema elementFormDefault="qualified" 
  targetNamespace="http://oracle.j2ee.ws/ejb/Hello/types" 
   xmlns="http://www.w3.org/2001/XMLSchema" 
   xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/"
   xmlns:tns="http://oracle.j2ee.ws/ejb/Hello/types" 
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
  <complexType name="sayHello"> 
    <message name="HelloServiceInf_sayHello"> 
      <part name="parameters"
        element="ns1:sayHelloElement"/> 
    </message> 
    <message name="HelloServiceInf_sayHelloResponse"> 
      <part name="parameters" 
        element="ns1:sayHelloResponseElement"/> 
    </message> 
    <portType name="HelloServiceInf">
      <operation name="sayHello"> 
        <input message="tns:HelloServiceInf_sayHello"/> 
        <output message="tns:HelloServiceInf_sayHelloResponse"/>
      </operation> 
    </portType> 
    <sequence> 
      <element name="String_1" nillable="true" type="string"/> 
    </sequence> 
  </complexType> 
  <complexType name="sayHelloResponse"> 
    <sequence> 
    <element name="result" nillable="true" type="string"/> 
    </sequence> 
  </complexType> 
  <element name="sayHelloElement" type="tns:sayHello"/> 
  <element name="sayHelloResponseElement" 
    type="tns:sayHelloResponse"/> 
  </schema>
 </types> 
 <binding name="HttpSoap11Binding" type="tns:HelloServiceInf"> 
 <soap:binding style="document" 
      transport="http://schemas.xmlsoap.org/soap/http"/> 
 <operation name="sayHello">
   <soap:operation 
      soapAction="http://oracle.j2ee.ws/ejb/Hello:sayHello"/> 
   <input> 
     <soap:body use="literal" parts="parameters"/> 
   </input>
   <output> 
     <soap:body use="literal" parts="parameters"/> 
   </output> 
 </operation> 
 </binding> 
 <service name="HelloService"> 
   <port name="HttpSoap11" binding="tns:HttpSoap11Binding"> 
     <soap:address location="REPLACE_WITH_ACTUAL_URL"/> 
   </port>
</service>
</definitions>

如果你观察这个WSDL,你会注意到它有一个对于HelloService web service的完整的描述,包括端口,操作和消息类型。WSDL是web service和它的客户之间的合约,并且它能够帮助自动生成客户代理。

Web services平台的另外两项关键技术是SOAP,被用来调用web service的协议,和UDDI,它提供了用来定位web services 的注册器。

对于这些技术的支持已经完全被集成到J2EE平台中了。让我们关注一下J2EE对于web services的支持。

使用J2EE作为Web Services的平台

J2EE 1.4为使用常规Java类或企业级Java Beans来创建和部署web services提供了一个全面的平台。以下表格给出了J2EE 1.4中包括的web service APIs的细节。

image

定义在Java Community Process的JSR 101之下的JAX-RPC,提供了创建和访问web services的Java API,因此它是使用J2EE平台创建和部署web services的“心脏和灵魂”。通过向应用程序开发者隐藏XML类型和Java类型映射的复杂性,以及处理XML和SOAP消息的底层细节,它提供了一个简单的,健壮的创建web services应用的平台。为了引入一个方法调用范式,它提供了两种编程模式:服务器端模式,使用Java类或无状态EJB开发web service 端点,和客户端模式,创建作为本地对象访问web services的Java客户端。JAX-RPC 1.1要求使用SOAP 1.1,并且实现与使用其他技术创建的web services之间的互操作性,比如微软的.NET。实现了J2EE1.4规范的应用服务器,比如OC4J 10.1.3和SUN的Java System Application Sever,提供了对于JAX-RPC的支持。

JAX-RPC的叫法有点用词不当,因为它既支持RPC类型的web services,也支持文档类型的web services。

Web Services部署模型

在J2EE 1.4之前,所有J2EE商家都使用他们私有的部署模型支持web services。J2EE 1.4为Java Web Services定义了部署模型。它为J2EE平台上的web services制定了开发,部署以及服务发布和使用的标准。

在这篇文章的后续部分,我将讨论基于Java的web services的部署和使用的细节。

有了J2EE 1.4对web services的支持,让我们学习使用J2EE平台来建造web service的方法。

使用J2EE创建一个Web Service

把web service创建成一个轻便的和可互操作的分布式组件不是一项琐碎的任务。如之前讨论的,你既可以把常规Java类,也可以把无状态EJB部署成web services。常规Java类被打包在一个web模块中,而EJB web services被打包在标准的ejb-jar模块中。

在这两种部署选择中,你会使用哪一个呢?

Java 类对无状态EJB:永无止境的争论

你会选择常规Java类还是EJB作为你创建web service的技术可能是一个长期的争论。Java类比EJB更容易开发,它是纯的Java对象,并且它不具有EJB带来的“额外辎重”。但是,EJB提供了几个很好的特点,比如被声明的事务和安全性,因此它使开发者将精力集中于建立商业逻辑,而不需要担心基础服务架构。EJB 3.0大大简化了设计模型,在它的规范中,EJB看起来就像常规Java类。

打包要求

无论你决定使用常规Java类还是EJB,你都必须把一些定义文件打包到你的WAR或ejb-jar中,这样你才能将你的组件作为Java web service展示出来。下面是分别基于EJB和Java类的web service的打包结构:

基于EJB 的web service的ejb-jar:

/META-INF/
    ejb-jar.xml    
    webservices.xml    
          oracle-webservices.xml    
    mapping-file.xml  
          wsdl/ wsdl 文件
ejb classes (包括端点和bean类)

常规Java web service的web 应用(.war)

/WEB-INF/
    web.xml
    webservices.xml    
    oracle-webservices.xml    
    mapping-file.xml    
    wsdl/        the wsdl 文件    
    /classes/(包括端点和bean类)
    /lib/

让我们讨论每一个部署时的定义文件和描述符:

WSDL:如前所描述。

端点接口:web service端点必须实现java.rmi.Remote接口,并且在端点接口中的每一个方法都必须抛出java.rmi.RemoteException异常。这个端点需要注册到模块(ejb-jar.xml或web.xml)的标准部署描述符中。你的部署描述符(比如,ejb-jar.xml)需要包括如下条目:

<service-endpoint>
          oracle.ejb21.ws.HelloServiceInf
</service-endpoint>

如下是一个Hello World web service的端点的代码:

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

Web service部署描述符:J2EE平台需要一个名叫webservices.xml的部署描述符。它指定了部署到J2EE应用服务器所需的全部web service描述符,以及它们与容器资源和服务的依赖关系。同时,它还指定了:WSDL的位置;mapping.xml,它包含了Java到WSDL的映射;和Hello World web service的服务端点接口。在Resources章节中给出了一个与示例代码打包在一起的webservices.xml的例子。

商家规范部署描述符:一些实现规范参考,比如上下文根目录和端点地址,不能在web service部署描述符中指定。取而代之,你应该在商家规范部署描述符中指定它们。例如,如果你正使用OC4J,你将需要在WAR或ejb-jar中打包一个oracle-webservices.xml文件来定义那些属性。

Java-WSDL映射:这个文件定义了WSDL和Java类间的映射。映射文件没有标准的名字;web services部署描述符决定了它的名字。

在把你的组件部署为web service之前,你必须把所有的定义文件打包到WAR或ejb-jar模块中。有很多开发工具,比如Oracle JDeveloper,通过完成平凡的任务,比如生成部署描述符,映射文件等,简化了web service的开发。此外,大多数应用服务器都提供了web services装配工具,它们能够满足J2EE web service的打包要求。

除了理解组成一个web service的组件和相关的打包要求外,还有一些在你开发web service时必须解决的架构问题。

构建服务的途径

创建一个web service时的主要挑战是为服务确定合适的粒度。你可以新建一个服务,也可以展示一个由Java类或EJB创建的已经存在的组件并把它发布为一个服务。当创建服务的时候,你可以使用自顶向下方法或自底向上方法:

自底向上方法:这个方法允许把一个现有的Java类或EJB发布为web service。这是很流行的创建服务的方法,因为它使你不必重写应用程序,而是重用你现有的商业逻辑。如果你使用这种方法,你必须为你的web service实现添加一个web service端点接口,同时创建一个WSDL,它同其他部署描述符一样用来描述web service。由应用服务器提供的工具,比如Oracle Application Server的web service装配工具,通过生成WSDL,webservices.xml等描述符以及web services组件的映射文件使您的开发生活更加简单――这把开发者从手工创造那些文件的痛苦中解放了出来。

自顶向下方法:这是创建服务的“纯粹”的方法,它更适合于当你根据草稿创建服务的时候。你从使用WSDL来描述服务开始,而不是直接跳入到实现。这个方法比自底向上方法更优越,因为在开发web service的同时,由于对操作,信息和对WSDL的控制的仔细考虑,使得服务更容易使用,更可维护和更可互操作。一些J2EE厂商提供了工具使这种方法变得更容易,例如,Oracle Application Server的web services装配器能够生成接口,部署描述符以及你用来创建应用程序的类框架。

互操作问题

显然,你的web services在本质上的可互操作性是必要的。J2EE 1.4要求与Basic Profile 1.0(由Web Services:Interoperability(WS-I)机构指定)保持一致。当创建web services时,你必须在将它们部署到产品中之前测试它们的互操作性。

除了设计方法和服务互操作的需要,你可以遵循一些最优方法来使你的web service效用最大化。

最优方法

最佳实践

这里有一些开发web services的最优方法:

避免在你的应用程序中过度使用web services。检查你是否真的需要把你的应用程序发布为web service。

服务的模块性是很重要的。使用一个粗粒度的web service;例如:一个会话把你的商业逻辑封装为web service。

确定你设计了你的web service,以使它制造最少的网络通信量。

遵循WS-I基础框架。使用JAX-RPC数据类型作为调用你的web service的方法的参数,这样可以使它具有与异类web services的互操作性。如果互操作性对于你的应用程序来说很重要,那么请避免使用Collection,HashMap和List之类的数据类型作为你的web service的参数。

许多对于J2EE应用的传统最优方法也同样适用于web services。比如,避免把一个包含长时间事务的组件发布为web service。

权衡你的web service的安全需求和性能,因为安全性需要更高的开销。一个端到端安全的web service所需的性能开销是很高的。

J2EE蓝图应用软件Java Adventure Builder提供了一个很优秀的用来创建基于Java 的web services 应用的工具。

一旦一个web service完成了设计,开发和部署,那么能与之提供的服务相交互的客户端组件也会被随之创建。

调用 Web Services

一个web service的客户端可以是如下的任意一种:静态桩,动态代理或者动态调用接口(DII)。

创建一个web service客户端可能跟创建一个简单的web service一样复杂。幸运的是,J2EE 1.4为开发者简化了这一过程,你可以通过任何J2EE组件(即web客户端或EJB组件)来使用web services。

通过如下过程,你可以像使用JNDI访问其他任何资源一样来调用web service:

在你的组件的部署描述符中定义一个service-ref元素。例如,如果你从一个web模块来访问HelloWorldService web service,那么该模块的web.xml文件应该包含如下:

<service-ref>        
<service-ref-name>service/HelloWorldService</service-ref-name>
<service-interface>oracle.ws.HelloWorldService</service-interface>
<wsdl-file>META-INF/HelloWorldService.wsdl</wsdl-file>
<service-qname>urn:oracle-ws</service-qname>
</service-ref>

为了使你的应用程序能够找到web service,你必须在你的商家规范部署描述符中指定web service 的位置。例如,如果你使用OC4J从你的网络模块来查询web service,你的商家规范网络描述符orion-web.xml必须包含如下内容:

<service-ref-mapping name="service/HelloWorldService">
    <port-info>
      <wsdl-port namespaceURI="urn: HelloWorldService" 
                         localpart="HelloWorldServicePort"/>
    <stub-property>
         <name>javax.xml.rpc.service.endpoint.address</name>
         <value>http://localhost:8888/hello/HelloWorldInf</value>
    </stub-property>
   </port-info>
</service-ref-mapping>

在你的服务器中进行部署之前,你必须把端点接口和类文件打包到你的应用程序中。你可以通过JNDI查找来使用web service:

InitialContext ctx= new InitialContext();
HelloServiceInf hs = (HelloServiceInf)
             ctx.lookup("java:comp/env/service/HelloWorldService");
HelloWorld hello= hs.getHelloWorldServicePort();
String myhello = hs.sayHello("Debu Panda") ;
Java Web Services 的未来

正在形成的Web Services标准的推广

Web services平台已经成长为具有可靠性,安全性,事务性,易管理性,政策性等特性的平台。在web services领域有相当一部分已经出现或正在出现的标准。为了设计一套全新的Java API来推广那些正在形成的标准,在Java Community Process中有一些JSR正在完成中,下表列出了其中的一些JSR:

image

除了那些正在进化的标准,我们现在来领略一下下一代J2EE平台的主要版本对于web services的支持。

使用J2EE 5.0简化SOA的开发

使用J2EE创建面向服务的应用程序确实很困难,因此通过使用由JSR 181定义的Web Services 元数据注解,J2EE 5.0将使开发更简单。EJB 3.0和Web Services元数据具有相似的目标,就是向开发者提供亲和力。

为了在J2EE 1.4中开发一个简单的Java web service,你需要几个web service定义文件:WSDL,映射文件和几个冗长的标准以及私有的web services部署描述符。Web Services元数据规范使用一种类似于EJB 3.0的缺省配置方法来使开发更简便。Web Services元数据注解处理器(或web services 装配工具)会为你生成这些文件,因此你只需要关心类的实现。

当你使用Web Services元数据开发时,这是一个看起来如此简单的Java web service:

package oracle.jr181.demo; 
import javax.jws.WebMethod; 
import javax.jws.WebService; 
@WebService(name = "HelloWorldService", 
      targetNamespace = "http://hello/targetNamespace" ) 
public class HelloWorldService {        
@WebMethod public String sayhello(String name ) { 
     return "Hello” +name+ “ from jws";
    }   
}

正如我之前提到的,EJB 3.0使用常规Java类简化了EJB的开发。通过利用EJB 3.0和Web Services元数据,开发基于EJB的web services将会变得越来越简单。当使用EJB 3.0和web services元数据时,这是一个看起来如此简单的HelloWorld EJB web service。你不必担心创建WSDL,部署描述符等等,应用服务器会在部署过程中生成这些定义文件。

package oracle.ejb30.ws;
import javax.ejb.Remote;
import javax.jws.WebService;
@WebService  
public interface HelloServiceInf extends java.rmi.Remote{
@WebMethod java.lang.String sayHello(java.lang.String name) 
                              throws java.rmi.RemoteException;
}

如下是EJB 3.0中 HelloWorld EJB的实现类:

package oracle.ejb30.ws;
import java.rmi.RemoteException;
import javax.ejb.Stateless;
@Stateless(name="HelloServiceEJB")
public class HelloServiceBean implements HelloServiceInf {
public String sayHello(String name) {
 return("Hello "+name +" from first EJB3.0 Web Service");
 }
}

以上例子清楚的表明了通过使用web services元数据和EJB 3.0,服务开发正在变得越来越简单。

总结

在这篇文章中,你学习了使用J2EE平台创建web services的基础知识。现在,你可以在你最喜欢的实现了J2EE规范的应用服务中,比如Oracle Application Server 10g,Sun Java System Application Server等,开始创建和部署你的web services了。

资源

本文中使用的web service例子

“如何从一个现有的Java类开发一个Web Service”(.zip):

“如何从一个WSDL文档开发一个Web Service”(.zip):

“面向服务架构:Web Services之外” by Ted Farrell
“面向服务架构:部分1 & 2” by Samudra Gupta
“面向服务架构是什么?” by Hao He
OTN Web Services技术中心

版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
英文原文地址:
http://www.onjava.com/pub/a/onjava/2005/05/25/j2ee-services.html
中文地址:
http://www.matrix.org.cn/resource/article/43/43674_J2EE.html
 

组织简介 | 联系我们 |   Copyright 2002 ®  UML软件工程组织 京ICP备10020922号

京公海网安备110108001071号