如今,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可能会执行一个简单的功能,比如核算银行存款记录,也可能会是一个横跨多个商业过程的复杂的任务。
图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的细节。
定义在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平台的主要版本对于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 |