服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

ejb 2.1中实现web service

 


ejb2.1(enterprise javabeans 2.1)正式推荐版本已经出台,它产生的动力主要是enterprise javabeans对支持web service的需求,同时也是因为micr
osoft .net的发布,它对j2ee或者说对java技术来说已经构成了巨大威胁。在新版本的ejb2.1中,主要的变化主要集中在基于soap和wsdl的web service上。ejb已经成为一种新的web service平台。它对web service的支持主要体现在三个新的web service api上:分别是jax-rpc(java api for xml-rpc,它基本上是通过soap实现的java rmi,为rpc格式的soap消息提供远端接口)、saaj(soap api with attachments for java,它模仿soap消息的结构,同时也有功能有限的消息分发能力)和jaxm(java api for xml messaging,它类似于jms,提供发送和接收soap消息的消息架构),利用它们可以实现与其它类型的web service进行通讯,而且还允许无序的会话bean和消息驱动的bean来作为web service使用,使它们能够被任何与 soap1.1兼容的客户端所访问。例如:使用soap,我们就可以从其它平台web service来调用无序的会话bean的方法,象微软的.net,perl,apache axix和其他的语言和平台。ejb2.1中新的web service功能能够提供一种前所未有的跨平台互操作性,它主要是建立在两个崭新的j2ee soap工具包jax-rpc和jaxm。

web service代表了分布式计算的最新潮流,可能是自1995年java的出现和1998年xml出现以来最重要的技术了。其实,给web service下一个准确的定义是很难的,因为web service并不是任何特殊技术或者平台所特有的,web service是一种网络应用程序,以xml形式的文档,使用soap和wsdl进行信息交换。要更好地理解这句话的含义,你必须先理解soap和wsdl,下面是有关这方面的定义:

soap:简单对象访问协议(simple object access protocol),是在w3c的支持下,由microsoft,ibm和其他公司开发的,基于xml格式的一种协议,它是可伸缩和可扩展的,不象以前的dce rpc, corba iiop, java rmi-jrmp以及dcom,它已经被几乎所有的开发厂商所认可和接受。

wsdl:web服务描述语言(web service description language),也是在w3c的支持下,由microsoft,ibm和其他公司开发的,xml格式的语言,用来对web service进行描述,包括期望的消息格式类型、所使用的internet协议和web service的internet地址。

其实,web service代表了一种新的分布式对象技术,它和corba iiop和java rmi很相似,但也有许多差异,最大的差异应该就是真正的平台无关性。尽管java rmi和corba iiop都声称自己是平台无关的,但实际上,它们都需要它们自己的平台。要使用java rmi,你需要一个java虚拟机和java编程语言,对使用其它语言的开发者如visual basic或c++来说,java rmi并不是平台无关的。corba iiop也是有局限性的,iiop协议通常需要一个特定的架构如corba orb,也只有少数几个厂商支持corba。另一方面,web service着重描述信息交换的协议,而不是着重描述对这些协议的实现,换句话说,你可以用任何语言,在任何平台上,以任何你自己喜欢的方式来创建web service。

web service另外一个好处就是,不象其它的分布式对象体系,它建立在现有的技术架构的基础之上,因此大多说厂商很容易实现。soap和wsdl都是基于xml的,而xml已经被广泛支持,xml解析器在几乎每一种开发语言中都有,因此,处理soap消息和wsdl文档的基础已经存在了。此外,web service消息通常是通过tcp/ip进行交换的,也已经被几乎所有的平台和语言所支持。

jax-rpc和ejb

jax-rpc(java api for xml-rpc)实质上就是通过soap访问的java rmi。它和“本地的”java rmi (java rmi-jrmp)和java rmi-iiop很象,但是它是以soap作为通讯协议。要实现jax-rpc,最低要求是必须对通过http访问的soap支持rpc编码,但是,我们仍然可以提供对其他编码方式、消息格式和internet协议的支持。jax-rpc能够被用来从会话、实体和消息驱动的bean来调用web service的操作。jax-rpc能够用来访问其它平台的web service。例如:一个无序的会话bean可能会使用jax-rpc来调用.net web service的方法。如下图所示:


每个ejb开发商都会提供自己对jax-rpc的实现,但它们之间的差别是很小的,主要是因为所有的实现都必须遵照jax-rpc规范,jax-rpc能够当作客户端api来访问其它的web service,但是,它同时也是一个被称作“endpoint接口”的新型企业bean接口。当jax-rpc当作客户端api的时候,会话、实体或者消息驱动的bean能够使用它与其它平台的web service交换消息。jax-rpc定义了三种编程模型:generated stub、dynamic proxy和dii(dynamic invocation interface),我们在ejb环境中常用的generated stub模型。

如果使用jax-rpc去访问web service,那么,这个web service必须发行一个wsdl文档,ejb开发商提供的jax-rpc工具包产生java rmi接口和实现wsdl文档所描述的web service操作的stub,一旦stub和接口创建出来之后,我们就可以把它们与企业bean的jndi enc(environment naming context)进行绑定,然后与 web service进行通信。

wsdl把访问web service的接口描述成“端口”,每个端口有一个或者多个“操作”,端口和操作的概念和java的接口和方法类似。实际上,jax-rpc定义了wsdl和java rmi之间的映射关系,它产生来自端口的远端接口,并带有响应端口操作的方法。例如:一个wsdl文档可能描述一个被称作“bookprice”、并带有单个操作getboolprice的端口,下面就是bookprice wsdl文档的一些简单代码:

<?xml version="1.0"?>

<definitions name="bookprice"

targetnamespace="http://lucky.myrice.com/getbookprice"

xmlns:tns="http://lucky.myrice.com/getbookprice"

xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"

xmlns:xsd="http://www.w3.org/2001/xmlschema"

xmlns="http://schemas.xmlsoap.org/wsdl/">

<!-- 描述参数和返回值的message元素 -->

<message name="isbnmessage">

<part name="isbn" type="xsd:string" />

</message>

<message name="pricemessage">

<part name="price" type="xsd:float" />

</message>

<!-- 描述web service抽象接口的porttype元素 -->

<porttype name="bookprice">

<operation name="getbookprice">

<input name="isbn" message="tns:isbnmessage"/>



<output name="price" message="tns:pricemessage"/>

</operation>

</porttype>

<!-- 在这里进行绑定 -->

<!-- service元素告诉我们web service的地址 -->

<service name="bookpriceservice">

<port name="bookprice" binding="tns:bookprice_binding">

<soap:address location="http://lucky.myrice.com/bookprice" />

</port>

</service>

</definitions>

在部署的时候,jax-rpc stub生成工具会把wsdl端口转换成远程接口和stub,端口和服务stub可能是下面的样子:
 
public interface bookpriceservice extends javax.xml.rpc.service{

public bookprice getbookprice( ) throws remoteexception;

}

public interface bookprice extends java.rmi.remote {

public float getbookprice(string isbn)

throws remoteexception;

}

这里只是一个简单的例子,这个服务只有一个端口,而实际上一个服务会有多个端口,每个端口有相应的接口和stub。一旦接口和stub产生并被绑定到jndi enc之后,它们就可以在运行期调用web service的“操作”了,在下面的无序会话bean里,bookcatalog ejb利用jax-rpc从.net web webvices查找一本书的批发价格。
 
public class bookcatalog implements javax.ejb.sessionbean {

...

public float getwholesaleprice(string isbn) {

try {

initialcontext jndicontext = new initialcontext ( );

bookpriceservice service =

jndicontext.lookup("java:comp/env/service/bookpriceservice");

bookprice bookprice_port = service.getbookprice();

float price = bookprice_port.getbookprice( isbn );

return price;

catch(remoteexception re){

}catch(serviceexception se){

}catch(namingexception ne){

}

}
...

}

当调用getbookprice()方法时,jax-rpc stub向.net web service发送soap信息,stub产生的soap信息可能会是下面的样子:

 
<?xml version='1.0' ?>

<env:envelope

xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"

xmlns:xyz='http://lucky.myrice.com/bookprice"

encodingstyle="http://schemas.xmlsoap.org/soap/encoding/">

<body>

<xyz:getbookprice>

<isbn xsi:type="string">1565928695

</xyz:getbookprice>

</body>

</env:envelope>

.net erb services处理soap信息,并把结果返回到stub,stub分析结果,最后向客户端发送最终结果。

jax-rpc stub中的方法可以有参数,参数类型可以是基本数据类型,如int,long等;基本包装类型,如java.lang.interger,java.lang.long等;数组;java标准类型,如string,date等;也可以是自定义对象类型。自定义对象必须符合jax-rpc规范的规则。

除了产生stub外,jax-rpc也支持动态代理服务,除了它的远程接口和stub的实现是在运行时动态产生的之外,动态代理服务的作用和stub一样。下面的例子就是jax-rpc产生动态stub的

public class bookcatalog implements javax.ejb.sessionbean {

...

public float getwholesaleprice(string isbn) {

try {

initialcontext jndicontext = new initialcontext ( );

javax.xml.rpc.service service =

jndicontext.lookup("java:comp/env/service/dynamicservice");



bookprice bookprice_port = service.getport(bookprice.class);

float price = bookprice_port.getbookprice( isbn );

return price;

catch(remoteexception re){}

catch(serviceexception se){}

catch(namingexception ne){}

}

...

}

在运行时,getport()方法自动把bookprice接口映射到wsdl文档里定义的相应端口,然后产生stub实现接口的工作。

jax-rpc还支持名为dii(dynamic invocation interface)的动态api,dii允许开发人员在运行时调用soap方法。如果你使用过corba dynamic invocation interface的话,那你对jax-rpc dii一定很容易理解。jax-rpc dii类似于java的反射(reflection),它允许你以方法的形式得到一个代表web service操作的对象的参考,调用那个方法,就无需再访问service factory或者再使用stub和远端接口。下面的例子就是企业bean访问bookprice端口的getbookprice()操作:
 
public class bookcatalog implements javax.ejb.sessionbean {

...

public float getwholesaleprice(string isbn) {

try {

initialcontext jndicontext = new initialcontext ( );

javax.xml.rpc.service service =

jndicontext.lookup("java:comp/env/service/dynamicservice");

qname port = new qname("http://lucky.myrice.com/getbookprice ","bookprice");

qname operation = new qname("http://lucky.myrice.com/getbookprice",

"getbookprice");

call callobject = service.createcall(port, operation);

object [] args = new object[1]; args[0] = isbn;

float price = (float) callobject.invoke( args );

return price.floatvalue();

}

catch(jaxrpcexception se){}

catch(namingexception ne){}

}



}

...