<%@ page contentType="text/html; charset=gb2312"%> EJB 2.1中实现Web Service
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
EJB 2.1中实现Web Service
     发布者: 发布时间:2006-07-01
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){}


}





}


...


}

实际上,你可以在运行期配置参数、类型、编码等,你能用WSDL配置的所有信息都可以用DII动态配置。

JAX-RPC另外还是一个称为终端接口(Endpoint Interface)的新型组件,这个新接口允许我们把无序的会话Bean作为Web Service来实现,这个终端接口简化了javax.rmi.Remote接口的实现,并且遵守JAX-RPC规范中的规则。把一个无序的会话Bean作为Web Service来实现是非常简单的:只需定义Bean类和远端接口,然后使用开发商的提供的工具来实现。一旦建立了Web Service,它的方法就能够被任何SOAP兼容的、来自任何语言和平台的工具包来调用,比如:.NET,Perl,Apache Axis,C,C++等等。如下图所示:


由于JAX-RPC仅仅是Java RMI的另外一种形式,因此,利用它访问企业Bean是很自然的,我们以前已经利用RMI-IIOP和RMI访问过。利用JAX-RPC与EJB进行通信意味着EJB可以当作Web Service来使用,至少无序的Bean是可以的。EJB2.1允许我们利用JAX-RPC,但只能是应用于无序的Bean,这主要是因为SOAP是一种无序的消息协议,它没有对象识别的概念,因此它不能应用在有序的和实体的Bean中。

EJB2.1为无序的Bean定义了一个新的Web Service终端(EndPoint)接口,Web Service界的人使用“终端”来称呼发送和接收SOAP信息的任何东西。在EJB中,终端就是一个无序的会话Bean,它可以通过SOAP来访问,并且遵照JAX-RPC规范中定义的从Java-to-WSDL到Java-to-SOAP的映射规则。使用JAX-RPC最为EJB终端的基础是顺理成章的,因为JAX-RPC规范中定义了SOAP消息和Java方法调用以及从Java远程接口产生WSDL文档的详细规则。

不象EJB开发者已经很熟悉的远端和本地接口,终端接口并没有继承EJB对象类型,如EJBObject或EJBLocalObject。相反,终端接口直接继承了javax.ejb.Remote接口。例如:在上面的例子中的BookPrice的Web Service能够很轻易实现为EJB中的终端。下面的代码说明了一个BookPrice的终端接口,和实现为Web Service的无序会话Bean的部分列表。


public interface BookPrice extends javax.rmi.Remote {


public String getBookPrice(String isbn) throws javax.rmi.RemoteException;


}


public class BookPriceWS implements BookPrice, javax.ejb.SessionBean {


public float getBookPrice(String isbn){


Connection con = null;


Statement stmt = null;


ResultSet rs;


try {


DataSource ds = jdniEnc.lookup("java:comp/env/jdbc/DataSource");


con = ds.getConneciton();


stmt = con.createStatement();


rs = stmt.executeQuery("SELECT wholesale FROM CATALOG WHERE isbn = ´"


+isbn+"´");


if(rs.next()){


float price = rs.getFloat("wholesale");


return price;


}else{


return 0;


}


}


catch (SQLException se) {


//处理异常


}


}


...


}

终端接口比远程和本地接口一个很明显的好处就是它不会带来象EJBObject或者EJBLocalObect无用方法等形式的额外负担,此外,终端接口没有包括home接口,SOAP不支持按引用传值。因此,你不能要求一个Web Services接口(home 接口)按引用传递到另外一个远端接口,更进一步讲,你不能创建或移除一个Web Service。

当我们把一个无序会话 Bean开发成Web Service时,首先定义一个终端接口,然后利用它产生JAX-RPC的客户端Stub和WSDL文档或者如果你产生JAX-RPC客户端Stub,无需做任何改变,你可以把它包装成J2EE客户端JAR,利用它去访问无序会话Bean,利用SOAP做通讯协议。如果你从终端接口产生WSDL文档,其它的SOAP工具包也能够使用这个文档去访问你的无序Bean。WSDL和SOAP是Web Service的基础,因此,为EJB Web Services发布WSDL可以实现与其它平台的交互。

SAAJ

SAAJ(SOAP with Attachments API for Java)是一个基于API的SOAP工具包,它定义了SOAP Messages with Attachments (SwA)和SOAP用的MIME信息格式。Java开发人员能够利用SAAJ来创建、读取或者修改SOAP信息。这个API包含许多类和接口,用来定义SOAP元素(Envelope, Body, Header, Fault等),XML名称空间,属性,文字节点以及MIME附件。你可以使用SAAJ操作简单的、没有附件的XML格式的SOAP信息,也可以操作更加复杂的、带Mime附件的SOAP信息。SAAJ可以与JAX-RPC结合使用,但也可以单独使用,它有自己的、通过HTTP1.1实现的请求/应答方式的消息机制。

SAAJ是基于Abstract Factory模式的。SAAJ是类型的抽象集合,每一种类型的对象都是由SAAJ集合中另外的对象产生的。在Abstract Factory的SAAJ实现中,MessageFactory类是根,它负责创建自己的实例,反过来创建SOAPMessage,SOAPMessage包含SOAPPart,它代表SOAP文档、0个和多个AttachmentPart(代表附件的对象,如GIF,PDF等)。SOAPPart包含SOAPEnvelope、SOAPBody、SOAPHeader和其它类型的对象。

<?xml version=´1.0´ ?>


<env:Envelope


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


xmlns:xsi=´;http://www.w3.org/2001/XMLSchema-instance´;


xmlns:book=´;http://lucky.myrice.com/BookPrice´;


encodingStyle=´;http://schemas.xmlsoap.org/soap/encoding/´;>


<env:Body>


<book:getBookPrice>


<isbn xsi:type=´string´>1565928695


</book:getBookPrice>


</env:Body>


</env:Envelope>

而下面是用SAAJ创建的例子:

import javax.xml.soap.*;


public class Example_1 {


public static void main(String [] args) throws SOAPException{


MessageFactory msgFactory = MessageFactory.newInstance();


SOAPMessage message = msgFactory.createMessage();


SOAPPart soap = message.getSOAPPart();


SOAPEnvelope envelope = soap.getEnvelope();


envelope.getHeader().detachNode();


SOAPBody body = envelope.getBody();


SOAPElement getBookPrice = body.addChildElement(


"getBookPrice","book",


"http://lucky.myrice.com/BookPrice");


getBookPrice.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);


SOAPElement isbn = getBookPrice.addChildElement("isbn");


isbn.addNamespaceDeclaration("xsi",


"http://www.w3.org/2001/XMLSchema-instance");





Name xsiType = envelope.createName("type","xsi",


"http://www.w3.org/2001/XMLSchema-instance");


isbn.addAttribute(xsiType,"string");


isbn.addTextNode("1565928695");


message.writeTo(System.out);


}


}

如果我们对比上面的例子,就会发现SAAJ定义了SwA消息格式的准确结构,SOAP消息的属性和SAAJ类型之间可以发现是一一对应的关系:Envelope对应SOAPEnvelope;Body对应SOAPBody;getBoolPrice对应SOAPBodyElement;isbn对应SOAPElement(Text)等。

当然,上面的例子是很简单的,它并没有包含任何附件,SwA中的附件通常是二进制或者是其它的非XML格式的文件,它通常被SOAP文档引用。SAAJ靠JAF( Java Activation Framework)添加附件,并处理对象和数据流之间的相互转换。下面的这段示例代码利用SAAJ向SOAP附加一个PDF文件。

MessageFactory msgFactory = MessageFactory.newInstance();


SOAPMessage message = msgFactory.createMessage();


AttachmentPart pdfAttach = message.createAttachmentPart();


FileDataSource file = new FileDataSource("TestSAAJAttachment.pdf");


DataHandler pdfDH = new DataHandler(file);


pdfAttach.setDataHandler(pdfDH);


要成功处理附件,我们必须先理解JAF,JAF是处理MIME数据的极好框架,但它也有自己的局限性,大部分局限性与使用DataContentHandler类型有关。藏在JAF的局限性后面的细节问题是很复杂的,但我们可以使用JAF DataSource类型来克服大部分的局限性,就象例子中的javax.activation.FileDataSource那样。

SAAJ是一个用途广泛的API,可以让我们在几乎任何的应用中创建SwA消息,在某些情况下,我们可以与JAX-RPC一起在文字消息和SOAP消息中使用SAAJ,但也可以与其它的API如JavaMail,JMS,JAXM一起使用。如果Java应用已经创建了SwA消息,它仍可以使用SAAJ把这个消息转换成二进制流,然后与使用其它API的Web Services进行交换信息。

JAXM 和 EJB

JAXM (Java API for XML Messaging)是和(Java Message Service)类似的SOAP消息API,就象JMS是一种通过面向消息的中间件来发送和接收消息的API一样,JAXM是一种通过Web Service来发送和接收消息的API。
JAXM是面向文档的,它把SOAP消息以XML格式的文档来进行传送的。JAXM客户端都是使用SAAJ(SOAP with Attachments API for Java)来装配、接收和使用SOAP消息的,SAAJ模仿SOAP消息的实际XML结构,这种机制与JAX-RPC是有很大区别的,JAX-RPC使用方法调用的语法,把SOAP消息隐藏到了Java RMI代理的后面。使用JAX-RPC,你 所看到的是仅仅由方法、参数、返回值组成的远端接口,而使用JAXM,你直接处理SOAP协议。象JAX-RPC一样,JAXM必须与SOAP兼容的Web Service交换SOAP信息。例如:一个企业Bean可能使用JAXM与用Perl写的Web Service交换SOAP信息。EJB2.1开发者能够以JAXM作为一种新的消息驱动Bean的基础,我们称它为基于JAXM的消息驱动Bean(JAXM-MDB)。JAXM-MDB使用的是SOAP消息,但扮演的是Web Service的角色。JAXM-MDB能够实现单向的异步接口,就象基于JMS的消息驱动的Bean,也可以实现请求/应答式的同步接口。
JAX-RPC和JAXM都允许企业Bean访问不同平台上的Web Service,也可以作为用无序和消息驱动Bean建立的Web Service的基础。但是,由于缺乏厂商的支持,JAXM的使用前景并不是很乐观。
(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
MD5的Java Bean实现
EJB设计模式
提高EJB性能的十大技巧
Enterprise JavaBeans 入门
EJB 编程模型
实战EJB之- 开发和部署你的第一个EJB
 
最近评论:
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(7026)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(8508)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(9795)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(5008)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(3968)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(9396)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(6642)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(2775)
        
你曾悄悄的来过!
wow gold,wow gold,wow gold,ffxi gil max(3472)
        
冰封的往事!
wow power leveling,wow gold,WoW Gold,wow gold max(2736)
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号