监理公司管理系统 | 工程企业管理系统 | OA系统 | ERP系统 | 造价咨询管理系统 | 工程设计管理系统 | 签约案例 | 购买价格 | 在线试用 | 手机APP | 产品资料
X 关闭
上海OA快博

当前位置:工程项目OA系统 > 泛普各地 > 上海OA系统 > 上海OA快博

EJB 2.1中实现Web Service

申请免费试用、咨询电话:400-8352-114

AMTeam.org

EJB 2.1中实现Web Service

EJB2.1(Enterprise JavaBeans 2.1)正式推荐版本已经出台,它产生的动力主要是Enterprise JavaBeans对支持Web Service的需求,同时也是因为Microsoft .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) {

file://处理异常

}

}

...

}


终端接口比远程和本地接口一个很明显的好处就是它不会带来象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和其它类型的对象。

要迅速了解SAAJ,我们先用XML格式建立一个简单的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: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的使用前景并不是很乐观。

发布:2007-03-25 10:36    编辑:泛普软件 · xiaona    [打印此页]    [关闭]
上海OA系统
联系方式

成都公司:成都市成华区建设南路160号1层9号

重庆公司:重庆市江北区红旗河沟华创商务大厦18楼

咨询:400-8352-114

加微信,免费获取试用系统

QQ在线咨询