站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题JSR 109:J2EE应用系统内部的Web Services

JSR 109:J2EE应用系统内部的Web Services

摘要:

JSR 109:J2EE应用系统内部的Web Services

翻译作者: cocoqin
by Al Saganich 08/07/2002
原文链接:http://www.onjava.com/pub/a/onjava/2002/08/07/j2eewebsvs.html

  近六个月来,有关Web services生命周期,安全,协作,事务方面的许多标准纷纷出现。JSR已经开始用一种标准的方式来定义Web services的各个方面如何从J2EE应用服务器中得到支持。


  JSR 109专门讨论本地客户端如何访问Web services,服务器生命周期和Web services的部署。JSR 104,105和106联合在一起来描速web服务安全,包括信任服务的API,数字签名和加密。JSR 156 和157定义支持Web services的事务和合作的基础,包括支持2PC (JTA) 和商业事务。本文将介绍JSR 109 的内容并考察它对Web
  services在J2EE环境中实现的影响。


  JSR 109: Web'>http://jcp.org/en/jsr/detail?id=109">Web Services 在J2EE上的实现。当前规格说明书状态:版本0.3(正式发布版本 1.0) 15-April-2002



JSR 109介绍


  在过去的这些年里,J2EE成为提供web服务的主流标准。同时也出现了许多把应用端功能移植至web前端之后的标准, 其中Web services是最新的。J2EE一开始使用的是servlets,JSP和无状态会话企业java
  bean, 然后EJB规范发生了调整开始支持有状态的企业java bean, 在后来是实体bean, 最后开始支持基于消息的java bean。


  毫无疑问J2EE将会继续的发展和进步。JSR 109是最新的描述扩展J2EE的规格文档之一。JSR 109 定义了J2EE应用服务器应该如何以一种标准的方式提供对Web
  services的部署,管理和访问的本地支持。 明确的说,JSR 109覆盖以下重要的领域:



  在这篇文章里,我们要考察JSR 109的许多领域来理解每个领域到底带来了什么样的好处。但是在读这篇文章的时候,你要记住规格说明文档是描述解决问题的结论。我们在研究一种技术的时候常常只是注意它能做什么而忘记它要解决的问题是什么。在我们读这篇规格说明文档的时候,我们要一直问自己“它究竟要解决什么问题?”  规格说明文档描述解决问题的结论,它描述的范围不应该宽于也不应该窄于问题的范围。


  首先,JSR 109 尝试定义一种实现Web services的编程模式,在这种模式下无论Web services是如何实现的,对调用端来说看起来都是一样的。因为Web  services同时被其他很多的规范所控制和定义,JSR 109不可以要求Web services在实现和部署范围以外有任何的改变。我们来简单的看看部署和部署模式。

   JSR 109 尝试定义一种模拟其它J2EE编程模式的客户端编程模式;熟悉“传统”远程方法调用的开发人员会很容易的理解JSR 109。所谓的“传统”,我们指JSR  109定义了一种和其他J2EE应用一致的客户端编程模式,使用JNDI等方式来获取远程接口然后调用引用的对象。


  注意:一些支持Web services的公司,比如说Sun 和 BEA,他们表示对JSR109持有保留意见。需要查看完全的描述,参考http://jcp.org/en/jsr/results?j=109&t=1&c=1">投票内容。



客户端编程模型


  JSR 109客户端编程模式的目的是清楚的定义java应用如何能够像访问EJB那样访问Web service。这个问题只是许多复杂情形中的一种。其它的JSR定义和应用服务器不在一起的Web  services的访问;然而,这种方式给客户端应用带来了一定的编程复杂度。在部署Web service的应用服务器内部访问Web service我们定义为直接访问。JSR
  109的客户端编程模式定义了一种简单易懂的访问本地部署的Web service的方式。


  三种模式


   JSR 109定义了三种客户端编程模式――用户管理端口访问模式,容器管理端口访问模式,动态端口访问模式。我们将侧重于用户管理访问模式,这种模式基于原来的WSDL为Web  service定义了一个接口。使用用户管理访问模式的时候,应用系统需要为一个特定的接口提供一个端口。容器管理端口访问模式和用户自管理模式类似,但是容器直接管理对实例的调用,而用户只是申请一个普通的可以访问不同接口的端口。


端口 在了解Web service之前,我们必需先理解端口的概念。一个端口是Web service的一个实例。一个客户应用访问Web service必需通过服务接口访问服务,这时应用服务器可能启动一个已经存在的实例或者创建一个新实例来实现这个请求。熟悉EJB编程模式的读者会发现JSR  109的客户端编程模式非常熟悉。


  动态端口访问模式不需要事先了解WSDL的定义,调用会在端口不工作的时候发生。虽然明显看来动态端口访问模式更加强壮,但是在现实应用中动态端口访问模式并没有多大用处。在将来――当动态编程变得更加普遍的时候――这种方式也许会是非常有用的。本文的余下篇章中,我们将使用更加传统的容器管理端口访问模式,在这种模式里用户事先知道Web  service接口的定义。我们待会再解析用户管理端口访问模式和容器管理端口访问模式。


  第一步:首先我们得到一个在任何JNDI客户系统中都要用到的InitialContext。(对JNDI的描速已经超出了本文的范围,有兴趣的读者可以直接访问JNDI培训)当我们考察Web  services部署的时候,我们将了解访问Web service实际名称的细节;直到这个时候,我们才需要使用Web services的名称。当然,应用服务器应当保证实际的Web
  services已经被绑定到JNDI树上了。


例1.用户管理端口访问模式

  00 InitialContent ic = new InitialContext();

  01 SomeSpecificServiceInterface srv = (SomeSpecificServiceInterface)ic.lookup (java:comp/env/service/SomeSpecificServiceInterface);

  02 ServiceInstance si = (SomeSpecificService)srv.getServiceInstancePort();


  让我们来逐行研究这个程序片断,行00是传统的JNDI查找。行01,我们得到接口ServiceInterface的一个特定实例。所有的服务都需要实现Services接口,这个接口定义了访问服务的一些公用方法,例如返回特定实例。如果你熟悉EJB规范,你将发现Services接口和EJB本地接口有类似之处。行02,我们得到了定义了实际使用的方法的远程对象的一个实例。


  当Web service的定义在开发的时候已经完全已知的情况下我们一般使用用户管理端口访问模式。如果因为某种原因应用服务器不能返回支持行01 cast操作的实例,异常将会被抛出。


例2.容器管理端口访问模式

  00 InitialContent ic = new InitialContext();

  01 Service srv = (Service)ic.lookup

  (java:comp/env/service/SomeSpecificServiceInterface);

  02 ServiceInstance si = (SomeSpecificService)srv.getPort();


  例2和例1仅有很小的差别。在01我们只需要对象的一个公用接口。没有指定返回的接口名称,所以容器可以自由的返回任意的匹配被请求的JNDI名称的实例。行02也有一些差别:我们使用一个普通的getPort()调用方法而不是像我们在例1中使用的那种特定名称的get  port>Port调用方法。


  规格说明书中声明当用户仅仅访问对象的服务定义时可以使用容器管理端口访问。行02假定客户端知道服务可能不支持的一个特定接口。如果容器不知道所需求的cast操作,异常将被抛出。更可能的是,客户端在build的时候没有一个完全的WSDL定义,因此他们不能用the  getPort()方法,但是他们会指定合适的实例类型――这种方式看起来更可行。



  服务器编程模型


  服务器编程模式可能是JSR109最重要的部分。理解Web service在不同的生命周期的工作方式将帮助Web service开发人员创建在不同条件下都可以按预定方式工作的Web
  service。EJB规格说明书定义了不同类型EJB的生命周期。JSR 109更进了一步,它扩展了EJB模式,定义了Web services如何在Web  services容器里工作。JSR 109 关于服务器编程的定义是一个解决行为一致性的尝试。


快速背景贴士 Web 应用和EJB 一般在“容器”内执行。容器提供EJB或者Web 应用运行时需要需要的所有服务。事务,JNDI,JDBC,所有类似的服务都由容可提供。一般来说,一个应用服务器里有两种容器――Web 应用容器和EJB容器。它们都提供相似的服务,比如生命周期管理,但也会有微小的差异,这个要看提供的是何种服务。Web应用容器知道如何加载servlets;EJB容器知道如何加载EJB。


  在我们了解JSR 109规范内容之前,让我们先了解我们需要什么来支持Web services顺应J2EE的工作方式。首先,Web service的实现应该对客户透明。Web  service在应用服务器内实现这个事实不应该改变客户端对服务行为的认识。况且我们需要在很多的应用服务器里使用Web service。因此,编程模式应该是轻便强壮的,不仅支持现在的实现也要支持将来的实现。


  另一点比较重要的是和现存J2EE服务的无缝整合,例如 JDBC。我们希望我们的Web services能够方便的利用J2EE现存的优势而不危及到服务自身的完整性。


  有了这些目标,JSR 109定义了对Web services两个领域的支持:无状态会话bean和servlets。JSR 109一个让人失望的地方是它在没有解释的情况下忽略了消息驱动bean的定义。消息bean支持可扩展的同步消息,这是Web  services的一个重要部分。由于消息bean的行为可以被无状态bean和servlets所模拟,所以我们需要编写额外的代码。


  在Web services里端口的定义十分重要,JSR 109 定义了在J2EE应用服务器里如何将端口和服务进行映射。Web service的端口在概念上类似于JVM里的实例。



用无状态会话bean实现Web Services 


  JSR 109 一个很棒的地方就是无状态会话bean可以被用来简单快速的开发Web services。那些没有足够EJB背景的人可以通读EJB关于无状态bean的规格说明书。规格说明书中对实施Web services很重要的部分以下说明。



  以上的所有方面的定义适用于新的Web services。那么我们可不可以把现有的EJB作为Web services呢?因为EJB遵循规格说明书的规范,也没有违反JAX-RPC的规定,它是可以作为一个现存服务的实现来部署的。实际上,从EJB容器的角度出发,EJB和服务并没有实际的区别。


  无状态会话bean在EJB容器里执行。容器本身控制了bean的生命周期,包括创建和消灭bean的实例。图1显示了无状态会话EJB的生命周期。考虑到大部分的应用服务器都支持“缓冲”或者“预先创建”对象实例的概念来提高应用效率。我增加了一个额外的“概念性”的状态来表示“已缓冲”。

  

  图1。无状态会话EJB的生命周期



  Beans 因为许多原因转换状态。了解bean为什么进行状态的转换将帮助你理解如何开发行为正确的bean:


 1. 事务1 表示bean的第一次创建。一般来说,应用服务器会预先创建一定数量的bean;然而,如果正在被使用并且有足够的空间,一个新的bean的实例将在客户访问的时候创建。新创建的bean在被使用之前,会调用它自己的init()方法进行初始化 。任何一次性的初始化工作都可以在这里完成。


 2. 事务2表示从一个pooled状态到method-ready状态的转变。这种转变发生在当一个pooled的实例被分配给一个客户的时候,一般是通过get<...>Port()方法调用。和刚才说得一样,pooled状态的存在是提高启动性能。


3. 事务3只是一个简单的“例行工作”。对象的一个实例被分配给一个客户然后客户调用方法。


4. 事务4发生在对象被释放的时候(例如:设定变量为null)或者从任何范围被调离的时候。基于应用服务器的不同实现方式,bean转换为pooled状态然后被初始化或者直接转变成does-not-exist状态。


5. 事务5发生在bean被实际撤除的时候。destroy()方法被调用,在这里用户可以取消在init()方法里做的任何事情。


关于事务:现在Web services不支持事务处理,在bean方法被调用的时候任何事务都将被挂起。就是说,这意味着bean不可以指定或者需要事物context,因此,不可以被标志为事务“强制性”。



用Servlets实现Web Services


    用servlet和用EJB实现Web services从概念上并没有很明显的不同。选择servlet作为实现工具完全是个人喜好。用servlet来实现Web
  services需要遵循和EJB实现相同的原则。这两种方式的不同在于底层实现方式。表1显示了一些最明显的不同之处。


  我们要指明的是这些不同是作者的观点而不是出自JSR 109的内容。


<table cellSpacing=0 cellPadding=0 width="97%" border=1 &nbsp;>

&nbsp; 表1:EJB和servlet实现的不同
&nbsp;
&nbsp;

<tr>
&nbsp;&nbsp;&nbsp;
<td width="35%" height=25>
</td>
&nbsp;&nbsp;&nbsp;
<td width="27%">
Servlet
</td>
&nbsp;&nbsp;&nbsp;
<td width="38%">
EJB
</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>生存时间(Lifetime)</td>
&nbsp;&nbsp;&nbsp;
<td>Long-lived</td>
&nbsp;&nbsp;&nbsp;
<td>一般是short-lived,如果使用缓存周期会长一些</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>启动消耗(Startup overhead)</td>
&nbsp;&nbsp;&nbsp;
<td>Can be significant</td>
&nbsp;&nbsp;&nbsp;
<td>Normally light</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>内存印记(Memory footprint)</td>
&nbsp;&nbsp;&nbsp;
<td>Large </td>
&nbsp;&nbsp;&nbsp;
<td>

&nbsp;&nbsp;&nbsp; Small</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>容器服务支持(Container Services support)</td>
&nbsp;&nbsp;&nbsp;
<td>Some</td>
&nbsp;&nbsp;&nbsp;
<td>Significant</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>
生命周期(Lifecycle-aware)</td>
&nbsp;&nbsp;&nbsp;
<td>Marginally</td>
&nbsp;&nbsp;&nbsp;
<td>Very</td>
&nbsp; </tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>事务(Transaction)</td>
&nbsp;&nbsp;&nbsp;
<td>Unsupported</td>
&nbsp;&nbsp;&nbsp;
<td>Must not be required</td></tr>
&nbsp;
<tr>
&nbsp;&nbsp;&nbsp;
<td>Must implement(必需实现)</td>
&nbsp;&nbsp;&nbsp;
<td>javax.servlet.SingleThreadModel</td>
&nbsp;&nbsp;&nbsp;
<td>javax.ejb.SessionBean</td>
&nbsp; </tr>
<tr>&nbsp;&nbsp;&nbsp;
<td>Scales(性能)</td>
<td>Poorly</td>&nbsp;&nbsp;&nbsp;
<td>Well</td>&nbsp; </tr>&nbsp;
<tr>&nbsp;&nbsp;&nbsp;
<td>When you might choose(什么时候选择使用)</td>&nbsp;&nbsp;&nbsp;
<td>当需要很小数量的 long-lived方法并且不考虑启动消耗的情况下</td>
<td>当需要大量的short-lived调用</td></tr></table>

  Servlet 和 EJB方式的一个很重要的不同是生命周期的管理。正如我们在图 1上看到的那样,EJB知道它是通过init()方法调用被创建,通过destroy()方法调用被移除。Servlet的说明文档里没有类似的接口;为了支持相似的行为,JSR109定义了一个额外的接口―― java.xml.rpc.server.ServiceLifeCycle――来提供相似的行为。


&nbsp; Example 3. java.xml.rpc.server.ServiceLifeCycle

&nbsp; package java.xml.rpc.server;

&nbsp; public interface ServiceLifeCycle {

&nbsp; void init(Object context) throws ServletException;

&nbsp; void destroy();

&nbsp; }



&nbsp; 部署


  &nbsp; 部署解决了Web service使用细节和实现细节的分离。它既定义了打包也定义了命名/初始化。开发人员可能定义一些基于部署考虑是必需的,比如服务的名字和需要何种初始化,但是为了Web&nbsp;&nbsp; service能正确的工作,部署人员必需指定这些参数。JSR 109使用一个新的部署描述文件webservices.xml把它的部署架构于普通EJB或者Web&nbsp; 应用的部署之上。


  JSR109的如此定义使Web service的部署看起来和EJB部署非常类似。例4 显示了webservices.xml文件的大概样子,它包括5个主要元素。



  例4显示了webservices.xml文件的大概样子。需要指出的是,这个例子是基于规格说明书的.03版本,可能已经有所改变。代码很简单(完整的DTD可以在说明文档里找到),但是也需要一些解释。


  行12-16链接行05 的WSDL提供的Web service描述。EJB或者servlet都可以被指定为Web service的引擎,并且必需链接回先前定义的EJB或者servlet。行11定义了取得Web
&nbsp; service端口所需要的服务接口。行08 和 09 指定了Web service的外部名称,这样外部的用户就可以使用了。


Example 4. Sample webservices.xml

&nbsp; 00 <?xml version="1.0"?>

&nbsp; 01

&nbsp; 02 My first Web Service using JSP 109

&nbsp; 03 Sample

&nbsp; 04

&nbsp; 05 path.to.the.wsdl.representing.the.service

&nbsp; 06

&nbsp; 07 .. various optional elements such as description etc

&nbsp; 08 MyWebService

&nbsp; 09 qualifying.namespace

&nbsp; 10 name.within.namespace

&nbsp; 11 com.webservicesareus.webservice.sampleservInt



12

13 link to a named ejb

14 or

15 link to a named servlet

16


17


18


19



  JSR 109是一个定义Web services如何融合进J2EE应用服务的有趣文档。由于一些明确问题的存在,比如为什么Mbeans会被忽略,这个说明文档覆盖了需要被用来定义Web
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; services如何整合进现有的J2EE应用的主要领域。我将一直密切关注这个JSR和在安全方面一些类似的JSR。



原作者:


Al Saganich 是BEA系统公司的资深开发人员和企业JAVA技术工程师,主要研究java集成和XML,Web services系统。


↑返回目录
前一篇: Java开发者XML基础(一)
后一篇: WSIL简介(一)