WebLogic 7.0 的SOAP消息处理

日期: 2008-01-14 作者:MICHAEL GILBODE 来源:TechTarget中国

  WebLogic Server提供了将J2EE组件和Java类作为Web服务展示的机制。通过确定SOAP消息调用的操作、将SOAP消息中的操作的参数反串行化给Java程序,然后通过调用后端组件来处理RPC风格的Web服务。

  然而,有时,光这样做是不够的,Web服务需要访问SOAP消息。SOAP消息处理程序能够拦截对其他SOAP消息处理的请求和响应的SOAP消息。SOAP消息处理程序由基于XML RPC(JAX-RPC)的Java API定义。处理程序允许通过编程访问SOAP消息,并且经常用来处理SOAP消息头。SOAP消息头可能包含事务、安全和路由等信息。可以在SOAP消息处理程序中对消息头进行特定的处理。也可以使用处理程序向Web服务中添加其他功能,如缓存、加密和解密、日志记录和审计。也可以使用处理程序来处理SOAP附件。

  每个WebLogic Web服务包含一个或多个操作。可以将后端组件和SOAP消息处理程序结合起来实现操作。WebLogic支持的Web服务操作包括仅由后端组件实现的操作、后端组件和SOAP消息处理程序一起实现的操作、仅由SOAP消息处理程序实现的操作。

  SOAP消息处理程序被装配到处理程序链上–SOAP消息处理程序的顺序列表,可以应用到服务客户端或服务端点。每个WebLogic Web 服务可以定义一个或多个处理程序链。这些处理程序链然后再和合适的Web 服务操作相结合。

  在内部,WebLogic Web服务操作是通过处理程序链实现的。处理程序链以认证处理程序开始,后面是任何用户定义的处理程序,然后可能是一个调用后端组件的组件请求处理程序。

  消息处理程序生命周期

  SOAP消息处理程序必须作为无状态实例执行。JAX-RPC运行时系统将特定处理程序类的所有实例都看作是等价的。这就允许JAX-PRC运行时系统缓存处理程序实例,虽然并不要求这样做。

  处理程序的生命周期包含两个状态。处理程序要么就不存在,要么就处于就绪状态。处理程序实例有两个生命周期方法。Init()方法和destroy()方法允许创建处理程序实例的时候初始化处理程序,并在销毁实例的时候清除它。

  处理程序一旦处于就绪状态,就能调用它的各类handle()方法。在服务客户端上,在发送实际的SOAP消息之前调用handleRequest()方法,并且在接收到实际的响应之前调用handleResponse()方法。在服务端点上,在调用实际服务端点之前调用handleRequest()方法,并且在实际的响应发送给客户端之前调用handleResponse()方法。在服务客户端上,在接收到SOAP错误之前调用handleFault()方法,在服务端点上,在产生SOAP故障之前调用handleFault()方法。

  设计消息处理程序

  在设计SOAP消息处理程序时,必须确定处理程序的数目、处理程序的执行顺序以及是否要调用后端组件。

  在服务客户端和服务端点上都能配置任意数目的处理程序。调用处理程序的次序非常重要。例如,考虑服务端点上的处理程序链,它上面配置了加密处理程序和检查SOAP消息有效负载的缓存处理程序。为了让缓存处理程序能够读取并处理该消息,加密和解密处理程序必须已经破解了SOAP消息。

  WebLogic Web服务上的SOAP操作可以调用后端组件也可以不调用后端组件。不过,在运行的时候消息处理程序能够改变该行为。处理程序通过让自身的handleRequest()方法返回false就可以防止调用后端组件。实际上,这能避免调用处理程序链中剩下的任何处理程序。HandleResponse()和handleFault()方法返回false也能够避免对处理程序进行进一步处理。例如,考虑一个缓存处理程序。如果传入的请求已经缓存了结果,应该返回缓存结果并终止对处理程序的进一步处理。下面的代码就是一个例子:

  public boolean handleRequest(MessageContext context)
  {
  SOAPMessageContext smc =(SOAPMessageContext)context;
  if (Cache.exists(smc.getMessage())) {

  smc.setMessage(Cache.get(smc.getMessage()));
  return false;
  }
  return true;
  }

  处理程序链上的SOAP消息处理程序相互之间也可以共享状态。处理程序类中的每个handle()方法接受一个MessageContext作为参数。为了处理服务端点上的单个请求、响应、或故障处理,传递到handle()方法的MessageContext实例被共享到处理程序链上的所有处理程序实例中。Listing1中的两个处理程序共享了一个叫做"myProperty"的属性。Handler1设置该属性,而Handler2使用该属性。

  一些性能(如通过在handle()方法中返回false,并在所有处理程序中共享状态,来退出处理程序链的处理)在处理程序链中引入了处理程序之间的相互依赖性。必须预先规划并设计这些依赖关系,因为它们影响SOAP操作的执行。

  Listing 1

  public class Handler1 implements Handler {
  …
  public boolean handleRequest(MessageContext context) {
  context.setProperty("myProperty", "myValue");
  return true;
  }
  …
  }
  public class Handler2 implements Handler {
  …
  public boolean handleRequest(MessageContext context) {
  Object value = context.getProperty("myProperty");
  return true;
  }
  …
  }

  Listing 2

  <handler-chains>
  <handler-chain name="MyHandlerChain">
  <handler class-name="example.LogHandler">
  <init-params>
  <init-param name="logDirectory" value="c:/temp" />
  <init-param name="severityLevel" value="verbose" />
  </init-params>
  </handler>
  </handler-chain>
  </handler-chains>

  Listing 3

  QName serviceName = new QName(TARGET_NAMESPACE, "LogHandler");
  QName portName = new QName(TARGET_NAMESPACE, "LogHandlerPort");
  List handlerChain = new ArrayList();
  Map logConfig = new HashMap();
  logConfig.put("logDirectory", "c:/temp");
  logConfig.put("severityLevel", "verbose");
  handlerChain.add(new HandlerInfo(LogHandler.class, logConfig, null));
  Service service = factory.createService(serviceName);
  HandlerRegistry registry = service.getHandlerRegistry();
  registry.setHandlerChain(portName, handlerChain);

  实现消息处理程序

  JAA JAX-RPC处理程序必须实现javax.xml.rpc.handler.Handler接口。为了简化处理程序的开发,JAX-RPC提供了javax.xml.rpc.handler.Generic 处理程序抽象类。该类提供了默认的实现生命周期的方法和不同的处理方法。只有实现特定处理程序所需的方法才被覆盖。

  应该使用处理程序的生命周期方法来初始化和清除处理程序实例内部的资源。如果一个处理程序利用数据库连接这类资源,可以在init()方法中建立它,并在destroy()方法中清除它。

  初始化时,处理程序也能获得配置信息。该配置信息被作为HandlerInfo对象的一部分传递给处理程序实例的init()方法。例如,日志处理程序可能会收到像严重等级以及配置的日志目录这样的信息。如下所示:

  public void init(HandlerInfo handlerInfo) {
  Map handlerConfig =handlerInfo.getHandlerConfig();
  String severityLevel =
  (String)handlerConfig.get("severityLevel");
  String logDirectory =(String)handlerInfo.get("logDirectory");
  }

  根据是在服务端点还是服务客户端上销毁处理程序,在不同的上下文中调用handleRequest()和handleRepsponse()方法。对于类似于加密处理程序的这类处理程序来说这一点很重要。在服务客户端上,用handleRequest()方法加密消息,而用handleResponse()方法解密消息。然而,在服务端点上,却用handleRequest()解密消息,而用handleResponse()加密消息。通过创建客户处理程序和服务处理程序能够实现这一点。但是,由于这些行为本质上是一样的,所以将配置消息传递给处理程序来告诉它是在服务客户机上还是在服务端点上,也可以实现这一点。(列出了EncryptDecryptHandler.java的源代码就是这样的一个例子,本文的源代码在www.sys-con.com/weblogic/source.cfm中。

  配置消息处理程序

  WebLogic Web服务是通过使用配置描述文件来配置的。该文件叫做web-services.xml,位于托管该Web服务的WAR文件的WEBINF目录下。在该文件中指定了Web服务操作、实现Web服务的后端组件以及与Web服务相关的处理程序链。

  该文件和SOAP消息处理程序相关,因为它用来定义处理程序链,将配置信息传递给处理程序,并且将处理程序链和Web服务操作结合起来。处理程序和处理程序链是在Web服务配置描述文件的handler-chains段中定义的。Handler-chain段中包含一个或多个处理程序链定义,每个处理程序链定义中又包含一个或多个处理程序定义。Listing2是web-services.xml文件handler-chains段的例子。(完整的例子如源代码文件web-services.xml中所示。)该配置描述文件定义了单个叫做"MyHandlerChain"的处理程序链,它包含单个处理程序。使用处理程序元素中包含的信息来创建javax.xml.rpc.HandlerInfo实例,将它传递给处理程序实例的init()方法。在描述文件的初始参数段定义的参数名和值放置在Map中,通过HandlerInfo实例的getHandlerConfig()方法可以获得它。这允许处理程序实例在部署的时候获得配置信息。

  在客户端使用SOAP消息处理程序

  使用web-services.xml文件来配置消息处理程序链并且将它们和服务器上的SOAP操作结合起来。然而,也可以在服务客户端上使用处理程序。JAX-RPC规范没有指定任何标准的打包和部署模型。目前,J2EE 1.4规范和JSR 109正在完成这项开发工作。由于当前没有标准的JAX-RPC Web服务客户端容器,必须通过在服务客户端上编程来配置SOAP消息处理程序。

  为了将处理程序链和Web服务结合起来,开发者必须通过编程来创建处理程序链。处理程序链只不过是一个HandlerInfo对象列表。Listing3显示了如何在客户端上配置日志处理程序。(完整的列表在源代码文件Main.java中)。

  打包Web服务

  为了将WebLogic Web服务打包成标准的J2EE应用程序,需要通过下列步骤来装配使用消息处理程序的WebLogic Web服务:

  1、 创建web-services.xml文件

  2、 编译处理程序类

  3、 连编Web应用:将web-services.xml文件放到Web应用的WEB-INF目录中,并将处理程序类放在WEB-INF/classes中。

  4、 连编企业应用: Web服务的Web应用应该包含在企业应用中。

  5、 将企业应用部署到WebLogic服务器上:源代码文件build.xml是用来装配Web服务的Ant脚本的例子,其中Web服务调用了处理程序链及其组件。

  小结

  SOAP消息处理程序提供了一个实现Web服务的标准、灵活的方法。它允许在将后端组件展示成Web服务时还可以进行其他处理,并且不需要修改后端组件。在实现WebLogic Web服务时,SOAP消息处理程序非常有用。

 

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐