WEB开发网
开发学院软件开发Java 使用J2EE构建服务 阅读

使用J2EE构建服务

 2007-12-23 12:23:17 来源:WEB开发网   
核心提示:版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明英文原文地址:http://www.onjava.com/pub/a/onjava/2005/05/25/j2ee-services.Html中文地址:http://www.matrix.org.cn/resource/article/4

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

如今,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可能会执行一个简单的功能,比如核算银行存款记录,也可能会是一个横跨多个商业过程的复杂的任务。

使用J2EE构建服务(图一)
图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的细节。

使用J2EE构建服务(图二)
点击查看大图


定义在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:

使用J2EE构建服务(图三)

除了那些正在进化的标准,我们现在来领略一下下一代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技术中心

Debu Panda是Oracle Application Server开发小组的一个主要产品经理。进入讨论组讨论。

(出处:http://www.cncms.com)


Tags:使用 JEE 构建

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接