IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

Web 服务编程技巧和诀窍: 如何创建一个简单的 JAX-RPC 处理程序

测量执行请求所用的时间

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Andre Tost, 高级认证 IT 专业人员, IBM Software Group
Russell Butek (butek@us.ibm.com), 软件工程师, IBM Software Group

2004 年 5 月 01 日

当开发 Web 服务时,通常您并不想把特定于 Web 服务的代码放在实现中。在许多情况下,您会采用现有的代码,并且简单地将另一个访问层加入其中,也就是添加一种方法来通过 HTTP 之上的 SOAP 来调用它。这意味着服务实现对 SOAP 一无所知,它甚至连 XML 也不知道,调用它的客户端可能处于另一个进程中,可能在另一台机器上,甚至可能在地球的另一边。虽然这就是 Web 服务技术很出名的优点,但是它还是引起了一些难题,在本技巧中,我们就着手解决这些难题。

JAX-RPC 处理程序基础知识

JAX-RPC 处理程序允许您在服务调用的不同时间截获 SOAP 消息。处理程序既可以存在于客户端中,又可以存在于服务器端中。如果您在客户端使用 JAX-RPC,您就可以正好在 SOAP 请求消息进入网络之前让处理程序对其进行处理,并且在它返回到客户端之前,您还可以处理响应消息。类似地,在调用服务实现以及传出响应之前,您可以在服务器上截获传入 SOAP 请求消息。

可以将几个处理程序组合在一起,这称之为“处理程序链”。每个处理程序都处理 SOAP 消息,然后将其传送到链中的下一个处理程序。处理发生的确切序列是可配置的。在本文后面我们将再次讨论这个问题。

要开发一个 JAX-RPC 处理程序,您可以简单地创建一个类来实现 javax.xml.rpc.handler.Handler 接口。它有三种方法,可以分别用于处理 SOAP 请求、响应和故障。

处理程序生命周期


处理程序是在 JAX-RPC 规范中定义的。然而,“企业 Web 服务(Enterprise Web Services)”(JSR109)规范描述了如何在 J2EE 环境中使用它们,并且增加了一些对应用程序服务器管理处理程序的方式的说明(请参见 参考资料以获得关于这个规范更详细的信息)。在本文中,我们将假定您的 Web 服务运行在 J2EE 应用程序服务器上,因而将遵循 JSR109 以及 JAX-RPC 的定义。

处理程序是跨服务调用共享的。换句话说,它们可以存储仅仅对特定的客户端或服务器实例有效的信息。您可以将这与处理 Servlet 的方式相比较。当创建新的处理器实例时,就会调用它的 init() 方法。这使得您能够创建可用于多个调用的处理程序。在删除处理程序之前,会调用 destroy() 方法,这样您就可以清除它。然而,根据经验,您应该避免将任何状态完全存储在处理程序中。

处理程序配置


您可以程序化地配置处理程序,而在运行 J2EE 应用程序服务器的情况下,您也可以通过部署描述符来配置它们。处理程序和处理程序链是基于每个服务定义的。它们可以定义在服务器和客户端部署描述符中。 清单 1显示了我们的样本服务的部署描述符,它说明了处理程序类调用处理程序的方式。PerformanceHandler 是为 HelloWorld 服务注册的:

清单 1. 带有处理程序的 Web 服务部署描述符
   <webservices id="WebServices_1066491732483">
      <webservice-description id="WebServiceDescription_1066491732483">
         <webservice-description-name>HelloWorldService</webservice-description-name>
         <wsdl-file>WEB-INF/wsdl/HelloWorld.wsdl</wsdl-file>
         <jaxrpc-mapping-file>WEB-INF/HelloWorld_mapping.xml</jaxrpc-mapping-file>
         <port-component id="PortComponent_1066491732483">
            <port-component-name>HelloWorld</port-component-name>
            <wsdl-port id="WSDLPort_1066491732483">
               <namespaceURI>http://pack</namespaceURI>
               <localpart>HelloWorld</localpart>
            </wsdl-port>
            <service-endpoint-interface>pack.HelloWorld</service-endpoint-interface>
            <service-impl-bean id="ServiceImplBean_1066491732483">
               <servlet-link>pack_HelloWorld</servlet-link>
            </service-impl-bean>
            <handler id="Handler_1066493401322">
               <handler-name>handler.PerformanceHandler</handler-name>
               <handler-class>handler.PerformanceHandler</handler-class>
            </handler>
         </port-component>
      </webservice-description>
   </webservices>
                

上面定义了多个处理程序,这些处理程序形成了前面提到的链。

存储状态


如果参与一个服务调用的多个处理程序需要共享信息,它们就可以通过将属性添加到消息上下文(当它在处理程序之间传送时)来这样做。从请求到响应,这个消息上下文都是可用的。换句话说,我们可以使用它来将信息存储在传入请求中,而当响应返回时,我们又可以重用这些信息。在后面的示例中,我们将着手这样做。





回页首


示例:服务性能处理程序

现在,让我们看一看,您可以如何创建一个处理程序来测量服务实现的响应时间。我们假定您创建了一个 HelloWorld Web 服务,这个服务简单地返回一个字符串类型的消息。 清单 2显示了服务实现 Bean 的代码(您可以通过所有这些来源查找 EAR 文件,包括 参考资料部分中的一个测试客户端在内):

清单 2. Web 服务实现类
public class HelloWorld {
 
 public String helloWorld(String message) {
  return "Hello "+message;
 }
}
                

必须为托管该 Web 服务的服务器配置处理程序。它将在请求和响应消息中调用,这样我们就可以测量所用的时间。

初始化处理程序


如前所述,每个处理程序都必须实现 javax.xml.rpc.handler.Handler 接口。或者,您可以简单地继承 javac.xml.rpc.handler.GenericHandler 类来轻松地做到这一点,此类提供了所有方法的缺省实现。为了存储性能结果,我们可以使用称为 Logger 的类,我们把它放在 init() 方法中。您可以在 参考资料部分找到 Logger 类的来源。此外,应用程序服务器还将 javax.xml.rpc.handler.HandlerInfo 对象传入此方法,我们也需要它来进行缓存,请参见 清单 3

清单 3. 处理程序实现--初始化和销毁
public class PerformanceHandler extends GenericHandler {
 protected HandlerInfo info = null;
 protected Logger logger = null;
 public void init(HandlerInfo arg) {
  info = arg;
  logger = Logger.getLogger("c://temp//HelloWorldServiceLog");
 }
 
 public void destroy() {
  try {
   logger.close();
  } catch (Exception x) {} 
 }  
                

注意,在销毁处理程序实例时,我们关闭了 Logger 对象。

处理请求和响应


每个处理程序都实现 handleRequest 方法,该方法是在请求消息到达时调用的,如 清单 4中所示。

清单 4. 处理程序实现--handleRequest 方法
 public boolean handleRequest(MessageContext context) {
  try {
   Date startTime = new Date();
   context.setProperty("startTime", startTime);
  } catch (Exception x) {
   // insert error handling here
   x.printStackTrace();
  }
  return true;
 }
                

这里您可以看到,我们将消息上下文中的当前时间存储为名为“startTime”的特性。应用程序服务器将保证相同的消息上下文对象传送到 handleResponse 方法,这样我们就可以测量其中所用的时间,如 清单 5所示。

清单 5. 处理程序实现--handleResponse 方法
 public boolean handleResponse(MessageContext context) {
  try {
   Date startTime = (Date)context.getProperty("startTime");
   Date endTime = new Date();
   long elapsedTime = endTime.getTime()-startTime.getTime();
   logger.write("Elapsed time is "+elapsedTime+"\\n");
  } catch (Exception x) {
   // insert error handling here
   x.printStackTrace();
  }
  return true;
 }
                

现在,您可以配置您的服务了。确保您配置的处理程序与上面的部署描述符中所示的处理程序一样,并且您可以测量执行服务请求所用的时间。





回页首


总结

JAX-RPC 定义了一种机制,在这种机制中,您可以通过截获请求和响应消息来管理服务请求,而不必更改实际的服务消费者或提供者。在 J2EE 中,您可以将处理程序配置在部署描述符中,而无需编写任何代码,这为您提供了一种强大的方法,让您可以在 SOAP 消息通过您的系统时对其加以控制。



参考资料



作者简介

Andre Tost 是一位解决方案设计师,他在 WebSphere Business Development 组工作,在那里他帮助 IBM 的策略联盟(Strategic Alliance)合作伙伴使用 WebSphere 来集成他们的应用程序。他的主要研究方向是在整个 WebSphere 产品家族中使用 Web 服务技术。在承担现在的工作之前,他在 IBM 软件开发中作为开发人员及架构师已经有 10 年了,最近他主要是研究 WebSphere Business Components 产品。他来自德国,现在生活和工作在美国明尼苏达州罗彻斯特市。在他的空闲时间,他喜欢跟家人在一起玩或者看足球。您可以通过 atost@us.ibm.com与 Andre 联系。


Russell Butek 是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request(JSR) 专家组的 IBM 代表。他从事 Apache 的 AXIS SOAP 引擎的实现方面的研究,推动了 AXIS 1.0 遵循 JAX-RPC 1.0。以前,他是 IBM CORBA ORB 的开发人员和许多 OMG 特别工作组的 IBM 代表:包括可移植拦截器特别工作组(他是这个特别工作组的主席)、核心特别工作组以及互操作性特别工作组。您可以通过 butek@us.ibm.com与 Russell 联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款