WEB开发网
开发学院软件开发Java 消息中介的实用介绍——第 2 部分:使用中介路由消... 阅读

消息中介的实用介绍——第 2 部分:使用中介路由消息

 2009-10-21 00:00:00 来源:WEB开发网   
核心提示:引言本系列文章的第 1 部分介绍了中介的基本知识,现在您应该已知道了使用中介的原因和场合,消息中介的实用介绍——第 2 部分:使用中介路由消息,以及如何开发、组装、部署和测试简单的中介处理程序,在这第二篇文章中,以便可以根据消息的内容对消息进行处理,我们将扩展 DebugMediation 以输出消息内容,您将了解如何

引言

本系列文章的第 1 部分介绍了中介的基本知识。现在您应该已知道了使用中介的原因和场合,以及如何开发、组装、部署和测试简单的中介处理程序。在这第二篇文章中,您将了解如何使用中介路由消息。我们将首先描述在不使用中介的情况下如何路由消息,然后接着介绍使用中介扩展此功能的方式以及原因。

准备

要开发和测试本文包含的中介,必须安装以下软件组合之一:

IBM® WebSphere® Application Server Toolkit Version 6.0 与 IBM WebSphere Application Server V6

IBM Rational® Application Developer for WebSphere Software V6,包括集成的 WebSphere Application Server V6 测试环境。

IBM Rational Application Developer for WebSphere Software V6 与 WebSphere Application Server V6。

IBM Rational Software Architect V6.0,包括集成的 WebSphere Application Server V6 测试环境。

您还应该下载和应用所安装产品的最新服务水平。撰写本文时,所发布的最新 Fixpack 为 WebSphere Application Server V6 Refresh Pack 1 (V6.0.1)。可以使用 Rational Product Updater 来获得 Rational 产品的更新,Rational Product Updater 会在安装任何 Rational 产品时自动安装。

本文中所出现的屏幕图像均出自 Rational Application Developer V6。如果使用 WebSphere Application Server Toolkit,仍然可以采取本文中所述的步骤,因为这些步骤对于 Application Developer 和该工具包而言,是完全相同的。可以从 WebSphere Application Server 安装媒体或映象安装 WebSphere Application Server Toolkit。

最理想的情况是:您已经成功地按照上一篇文章中所述进行操作,已开发、部署并测试过一个中介处理程序。如果尚未读过上一篇文章,请确保按照本文后面所述的附加步骤进行相应操作。

使用受管理路由路径路由消息

WebSphere Application Server V6 的缺省消息传递提供程序会使目的地采用受管理路由路径,从而在将消息发送到目的地时提供一个简单的方法来路由消息。为了本文起见,我们将以一个简单的零售管理的例子来演示消息路由的一种可能的用法:

跨国大型超市公司的每家连锁店都通过电子方式与总部进行交互,以报告交易情况、订购量以及进行其他业务活动。销售点 (POS) 终端以及其他系统使用 JMS 消息传递与总部系统进行通信。为了获得更大的控制和灵活性,每个连锁店都使用一个专用的目的地。

为了确保将消息转发到总部系统,每个连锁店目的地都定义了一个到达中心目的地的受管理转发路由路径。实际上,每个连锁店目的地都作为要路由到中心目的地的消息的“下一个跃点”使用,这些消息将在中心目的地由总部系统进行处理。此消息路由拓扑如图 1 所示。
图 1. 使用路由路径转发消息的逻辑消息传递拓扑
消息中介的实用介绍——第 2 部分:使用中介路由消息

可以在目的地之间使用自动路由消息功能,以更好地实现组件、服务或应用程序之间的分隔。在本例中,没有使用中介就实现了消息路由,这引出了一个问题:为什么要使用中介进行路由呢?

使用中介路由消息

使用中介,可以对正在传递的消息进行有条件的处理;通过比较,可以发现受管理路由路径没有条件元素,此类路径应用到发送到目的地的所有消息。在我们的示例中,受管理路由路径的用法是有效的,因为需要将所有消息按照完全相同的方式进行路由。如果同一目的地的消息需要按照不同的方式进行路由,则不能使用受管理路由路径。如果需要有条件地路由消息,请使用中介。

对我们的示例进行修改,可以反映出需要进行选择性路由的一个原因:

此超市连锁公司开发了总部 POS 应用程序的新版本,此版本采用了不同的消息格式。解决方案以前基于 JMS 对象消息;新应用程序使用通过 JMS 文本消息发送的 XML 消息。该应用程序的新版本定义了接收消息的特定目的地,而该目的地使用新格式。当然,可以要求所有连锁店一起切换到新版本的应用程序,但更实际的方法则是让一些或全部连锁店开始只升级其部分 POS 终端。一旦证明应用程序的可靠性后,再将新应用程序推广到所有连锁店中的每个终端。

场景中的这一变化给我们提出了一系列简单的要求,可以用中介满足这些要求:最根本的,将调用中介处理程序检查消息格式,然后据此路由消息。此中介应用到每个连锁店目的地。调用中介时,中介会将 JMS 文本消息(格式为“JMS:text”)路由到为处理 XML 消息的新版应用程序定义的目的地。使用旧格式“JMS:object”的消息将不会修改其路由路径,因此将被路由到原来的中心目的地。

消息路由中介

前一篇文章中提供了关于如何开发和测试基本中介处理程序的详细说明,因此我们将主要讨论中介处理程序的代码。(如果尚未读过第一篇文章,则应该考虑读一读;其中的基本知识将不会在此处复述。)

中介参数和上下文属性

使中介处理程序具有可配置性,可以使其更便于进行重用;请考虑此“最佳实践”。组装中介处理程序时,工具安装过程将在 Java™ 类中查找可以公开为处理程序参数的字段。如果某个处理程序字段具有相应的 getter 和 setter 方法,则此字段可作为参数公开给您的中介处理程序。

简单 Java 原语在部署描述符中定义;通过在中介处理程序面板中选择参数并单击 Edit 按钮,可以进行赋值。调用中介处理程序转发消息之前,将使用部署描述符中定义的值设置处理程序的参数。引用对象的字段也可以作为中介处理程序参数公开。这些对象引用参数在部署描述符(将在运行时解析)中作为资源引用公开。中介的部署者必须确保资源引用映射到了恰当的对象,否则将会出现运行时错误。

要更改中介处理程序的参数,必须:

编辑部署描述符

更改参数

重新部署组装过的处理程序。

您可能希望通过为部分或全部参数提供覆盖机制以避免这些步骤。管理员可以在目的地和中介上定义上下文属性,这些属性可以在运行时使用 javax.xml.rpc.handler.MessageContext 引用进行检索,此引用会在调用中介处理程序时传递给它。使用上下文属性提供覆盖功能非常简单,稍后我们将在示例处理程序中举例说明。

我们将要公开一些属性,用于控制是否需要对某条消息进行路由以及应将其路由到何处。下表显示了中介处理程序的属性及其可以具有的效果。所有属性的类型都为 java.lang.String。

属性 用途
RouteMessageFormat要进行重新路由的消息的消息格式。可以对此值进行硬编码,但如果为可配置的,则中介处理程序的可重用性能更好。缺省情况下,将路由 JMS:text 格式的消息;可以在部署描述符中更改这一点,或者通过设置“RouteMessageFormat”上下文属性将其覆盖。(有关 JMS 消息的详细信息,请参阅 WebSphere Application Server Information Center。
RouteMessageDestination消息重新路由到的目的地。

开发消息路由中介处理程序

可以在下载文件中下载此中介的一个源代码版本,该文件中还包含一个用于创建测试消息环境的管理脚本。可以下载并导入所提供的中介代码,也可以按照以下步骤创建中介处理程序:

启动 Application Developer,并使用上一篇文章所使用的同一个工作区。如果没有此工作区,则:

创建一个名为 MessageMediation 的新 Java 项目。

使用项目上下文菜单选择项目属性,方法为右键单击此 Java 项目,然后从出现的菜单中选择 Project Properties。

选择 Server 属性,然后将 Target Server 设置为 WebSphere Application Server Version 6.0。

使用 Create Java Class 向导,向 MessageMediation 项目添加一个新的中介处理程序类。如图 2 所示,该类的名称为 RoutingMediation,软件包为 mediation.handlers,而且它必须实现 com.ibm.websphere.sib.mediation.handler.MediationHandler 接口。
图 2. 创建路由中介处理程序类
消息中介的实用介绍——第 2 部分:使用中介路由消息

需要在该处理程序类中添加两个字段,这两个字段与具有适当的 setter 和 getter 方法的中介参数对应。中介还使用标准 Java logging API 对消息进行记录。请添加清单 1 所示的代码。

清单 1. 路由中介参数和记录引用

// Mediation parameters 
  private String routeMessageFormat = "JMS:text"; 
  private String routeMessageDestination = "routeToQueue"; 
  // Used for logging and tracing the execution of the handler 
  private String logName = "MsgMediation"; 
  private Logger log; 
  public String getRouteMessageDestination() { 
    return routeMessageDestination; 
  } 
  public void setRouteMessageDestination(String routeMessageDestination) { 
    this.routeMessageDestination = routeMessageDestination; 
  } 
  public String getRouteMessageFormat() { 
    return routeMessageFormat; 
  } 
  public void setRouteMessageFormat(String routeMessageFormat) { 
    this.routeMessageFormat = routeMessageFormat; 
  } 
  private Logger getLog() { 
    if (log == null) { 
      log = Logger.getLogger(getLogName()); 
    } 
    return log; 
  } 
  public String getLogName() { 
    return logName; 
  } 
  public void setLogName(String logName) { 
    this.logName = logName; 
  }

当转发消息时,将调用 handle(MessageContext) 方法。我们的 handle 方法会将大部分处理委托给其他方法,请更改现有的 handle() method 以与清单 2 中的方法匹配。稍后我们将对所需的方法进行编码。

清单 2. 路由中介 handle() 方法

public boolean handle(MessageContext msgCtx) throws MessageContextException { 
    boolean contMsgProcessing = true; 
    SIMessageContext siMsgCtx = (SIMessageContext) msgCtx; 
    SIMessage msg = siMsgCtx.getSIMessage(); 
    if (shouldRouteMessage(siMsgCtx)) { 
      setRoutingPath(siMsgCtx); 
      getLog().log(Level.INFO, "Re-routed message {0}", msg.getApiMessageId()); 
    } else { 
      getLog().log(Level.INFO, "Message {0} does not require re-routing", msg.getApiMessageId()); 
    } 
    return contMsgProcessing; 
  }

shouldRouteMessage(MessageContext) 方法确定是否需要对消息进行路由;如果满足所定的条件,则将返回 true。这个操作是通过将待转发消息的消息格式与中介处理程序的配置值进行比较完成的。因为所需的消息格式可以由管理员覆盖,故而将调用 getRouteMessageFormat(MessageContext)。如果设置了消息上下文属性,此方法会返回此属性,否则它将返回定义的中介参数的值。这两个新方法都在清单 3 中给出。请将它们添加到该中介处理程序类中。

清单 3. 检查路由消息条件

private boolean shouldRouteMessage(SIMessageContext siMsgCtx) { 
    boolean result; 
    SIMessage msg = siMsgCtx.getSIMessage(); 
    result = msg.getFormat().equals(getRouteMessageFormat(siMsgCtx)); 
    return result; 
  } 
  private String getRouteMessageFormat(SIMessageContext siMsgCtx) { 
    String value = (String) siMsgCtx.getProperty("routeMessageFormat"); 
    if ((value == null) || (value.equals(""))) { 
      value = getRouteMessageFormat(); 
    } 
    return value; 
  }

如果消息需要重新路由,则调用 setRoutingPath(SIMessageContext) 方法来更改消息的路由路径。这将使用 com.ibm.websphere.sib.SIDestinationAddressFactory 查找要使用的目的地,以设置转发路径。与 getRouteMessageFormat(MessageContext) 类似,getRouteMessageDestination(MessageContext) 方法支持使用上下文属性管理目的地名称。请将清单 4 中所示的代码添加处理程序类中。

清单 4. 修改消息路由路径

private void setRoutingPath(SIMessageContext siMsgCtx) { 
    SIMessage msg = siMsgCtx.getSIMessage(); 
    List frp = new ArrayList(1); 
    String destName = getRouteMessageDestination(siMsgCtx); 
    SIDestinationAddress dest = SIDestinationAddressFactory.getInstance(). 
      createSIDestinationAddress(destName, false); 
    frp.add(dest); 
    msg.setForwardRoutingPath(frp); 
  } 
  private String getRouteMessageDestination(SIMessageContext siMsgCtx) { 
    String value = (String) siMsgCtx.getProperty("routeMessageDestination"); 
    if ((value == null) || (value.equals(""))) { 
      value = getRouteMessageDestination(); 
    } 
    return value 
  }

这样,我们就完成了消息路由中介处理程序所需的代码。现在就可以对其进行组装、部署和测试了。

组装、部署并测试路由消息中介

如果已按照前一教程所述进行了操作,则只需要在已经存在的 DeployableMediationEJB 项目中定义此处理程序。否则,将需要进行以下操作:

创建名为 DeployableMediation 的新 J2EE Enterprise Application 项目。

创建此项目时,请创建一个名为 DeployableMediationEJB 的新 EJB 项目,并将其添加到现有的 MessageMediation 项目。

编辑 DeployableMediationEJB 项目的 Java JAR 依赖性,并将 MessageMediation 项目添加为依赖性。

组装消息路由中介

要组装中介处理程序,请执行以下步骤:

打开 DeployableMediationEJB 项目的部署描述符。

选择 Mediation Handler 选项卡,如图 3 所示。
图 3. 编辑部署描述符中定义的中介处理程序
消息中介的实用介绍——第 2 部分:使用中介路由消息

使用 Add 按钮添加路由中介,并完成图 4 所示的面板。
图 4. 将处理程序类添加到部署描述符
消息中介的实用介绍——第 2 部分:使用中介路由消息

保存并关闭部署描述符。现在已经完成了中介处理程序的组装。

部署消息路由中介

如果已按照前一教程中所述进行了操作,则 DeployableMediation 企业应用程序可能仍然部署在服务器上。如果是这样的话,则只需确保更改已发布即可。如果未部署该企业应用程序,则按照以下步骤进行操作:

在所用部署工具的 Servers 视图中选择您的服务器。如果未定义任何服务器,则在服务器视图内单击右键,然后选择 Add and remove projects。

将 DeployableMediation 项目添加到服务器。

该项目现在应该自动添加到定义的服务器。如果有必要,可使用服务器上下文菜单强制发布该应用程序。

测试路由消息中介

在测试中介处理程序前,需要创建测试消息传递配置。下载文件中包括一个名为 routingMediationAdmin.jacl 的管理脚本,该脚本将创建:

两个目的地,originalQueue 和 routeToQueue。

一个 JMS Connection Factory,jms/CF2,它连接到总线 SimpleBus。

两个托管目的地(在 JNDI 中),名为 jms/originalQueue 和 jms/routeToQueue,并将它们链接到两个目的地。

一个名为 RoutingMediation 的中介,并将其应用到 originalQueue 目的地。

此脚本假定存在总线和总线成员。如果没有按照前一篇文章中所述进行操作,并且尚未定义总线,则请编辑此脚本文件,取消注释所包含的创建总线的代码:将下面的注释后紧跟的 # 字符删除:

# Uncomment the following section to create a messaging bus and assign the server as a member of the bus.

使用服务器的 Run external admin script 上下文菜单项运行该脚本(图 5)。导航到 routingMediationAdmin.jacl 文件并运行它。


图 5. 启动外部管理脚本
消息中介的实用介绍——第 2 部分:使用中介路由消息

图片看不清楚?请点击这里查看原图(大图)。

应该看到如下消息:

   Create SIB Queues 
$AdminTask createSIBDestination -bus SimpleBus -name originalQueue 
  -type queue -node neodogNode -server server1 
$AdminTask createSIBDestination -bus SimpleBus -name routeToQueue 
  -type queue -node neodogNode -server server1 
Create JMS JNDI Resources 
$AdminTask createSIBJMSConnectionFactory server1(cells/neodogNode04Cell/nodes/neodogNode/servers/server1|server.xml 
  #Server_1114261967144) -name CF2 -jndiName jms/CF2 -busName SimpleBus -type queue 
$AdminTask createSIBJMSQueue server1(cells/neodogNode04Cell/nodes/neodogNode/servers/server1|server.xml 
  #Server_1114261967144) -name originalQueue -jndiName jms/originalQueue -queueName originalQueue 
$AdminTask createSIBJMSQueue server1(cells/neodogNode04Cell/nodes/neodogNode/servers/server1|server.xml 
  #Server_1114261967144) -name routeToQueue -jndiNamejms/routeToQueue -queueName routeToQueue 
Create and apply RoutingMediation to originalQueue 
$AdminTask createSIBMediation -bus SimpleBus -mediationName RoutingMediation 
  -handlerListName RoutingMediation 
$AdminTask mediateSIBDestination -bus SimpleBus -destinationName originalQueue 
  -mediationName RoutingMediation -node neodogNode -server server1 
Configuration saved 

为了让对 JNDI 服务器的更改生效,必须重新启动服务器。一旦服务器重启后,就可以使用通用测试客户端 (UTC) 测试中介了:

使用服务器上下文菜单项启动 UTC。

展开 Utilities 选项卡,并选择 Send JMS Message 实用工具。

使用 jms/CF2 Connection Factory 向 jms/originalQueue 目的地发送一条消息,如图 6 所示。
图 6. 使用 UTC 发送消息
消息中介的实用介绍——第 2 部分:使用中介路由消息

使用服务器上下文菜单启动 WebSphere Application Server 管理控制台,应该看到如下消息(此消息将在单个行上显示):

[17/04/05 14:40:13:418 BST] 0000005d MsgMediaiton I Routing message ID: 
  8fa289e1aff0dd0876a80a48110a134f0000000000000001 


登录并展开 Service Integration 选项卡。

选择 Buses => SimpleBus => Destinations => routeToQueue => Queue points,然后选择所显示的队列点。

面板显示时,选择 Runtime 选项卡。

定位到 Current Message depth,其值应该为 1。此项与日志项均指示发送到 originalQueue 的消息已经被路由到 routeToQueue 目的地。

也可以选择按照下面的步骤进行操作,以证实已经对此消息进行了路由:

通过选择 Messages 浏览队列。

从显示的这个表中选择该消息。

由中介写入到日志中的消息标识符应与此目的地上的消息的 API 消息标识符匹配。

跟踪下载的中介处理程序

中介处理程序的下载版本包含有附加的跟踪和调试语句。通过使用标准 Java logging 接口,处理程序将写入记录项以跟踪其执行路径。为了查看跟踪项,请启用应用服务器中的跟踪功能。缺省情况下,所有实例中介使用的记录器的名称都为 MsgMediation。要使用管理控制台启用跟踪功能,请执行以下步骤:

展开 Troubleshooting 选项卡。

选择 Logging and Tracing => server1 => Change Log Detail Levels。

等待屏幕刷新完成,然后将日志级别更改为 *=info: MsgMediation=all。

重新启动服务器。将在服务器的日志目录中创建一个名为 trace.log 的文件。

向 originalQueue 发送另一条消息。中介将会把此消息写入跟踪记录文件,此文件可用于调试。

使用中介发送克隆消息

开发或集成使用消息传递功能的应用程序时,可能希望对消息流进行捕获。或者,您可能需要将消息的副本发送到另一个目的地,以用于审核或其他目的。中介处理程序可以使用 SIMediationSession 发送消息,通过对处理程序的 SIMessageContext 引用调用 getSession() 可以获得 SIMediationSession。SIMessage 消息将实现 java.lang.Cloneable,从而使中介可以进行克隆操作,然后将克隆消息发送到另一个目的地。下面让我们对示例进行进一步扩展,从而阐释可将中介用于此目的的原因和方式。

对新的 POS 应用程序进行最后测试时,需要捕获所有消息的副本,以验证发送到应用程序的所有消息都得到了正确的处理。另外,还可以通过这种方式对任何无法处理的消息的内容进行检查。

同样,中介处理程序需要具有可配置性,以便管理员能够定义一些属性,以控制克隆消息的创建和路由。下表显示了中介处理程序的参数及其用途,所有参数的类型都是 java.lang.String:

名称 用途
CloneMessageDestination克隆消息发送到的目的地。
ExistingRouteAction控制在消息具有现有路由路径的情况下采取何种操作。可能的值为 PREPEND、APPEND 和 OVERWRITE(缺省值)。
CloneMessagePropertyName要在克隆消息上设置的布尔属性的名称。设置此属性可以防止对已经克隆消息进行克隆。

开发发送克隆消息的中介处理程序

与前面的中介处理程序一样,此处理程序的源代码也可以下载,其中也包含跟踪和调试语句。对应的下载文件中也包含一个用于创建所需测试环境的管理脚本。要开发用于发送克隆消息的中介处理程序,请按照以下步骤进行操作:

创建新的中介处理程序类 mediation.handlers.SendCloneMediation,该类将实现 com.ibm.websphere.sib.mediation.handler.MediationHandler。

向该类添加具有恰当 setter 和 getter 方法的中介参数及记录引用,如清单 5 所示。

清单 5. 中介参数和记录引用

// Mediation parameters 
  private String cloneMessageDestination = "clonedMsgQueue"; 
  private String existingRouteAction = "OVERWRITE"; 
  private String cloneMessagePropertyName = "messageCloned"; 
  // Used for logging and tracing the execution of the handler 
  private String logName = "MsgMediation"; 
  private Logger log; 
  private Logger getLog() { 
    if (log == null) { 
      log = Logger.getLogger(getLogName()); 
    } 
    return log; 
  } 
  public String getCloneMessageDestination() { 
    return cloneMessageDestination; 
  } 
  public void setCloneMessageDestination(String cloneMessageDestination) { 
    this.cloneMessageDestination = cloneMessageDestination; 
  } 
  public String getCloneMessagePropertyName() { 
    return cloneMessagePropertyName; 
  } 
  public void setCloneMessagePropertyName(String cloneMessagePropertyName) { 
    this.cloneMessagePropertyName = cloneMessagePropertyName; 
  } 
  public String getExistingRouteAction() { 
    return existingRouteAction; 
  } 
  public void setExistingRouteAction(String existingRouteAction) { 
    this.existingRouteAction = existingRouteAction; 
  } 
  public String getLogName() { 
    return logName; 
  } 
  public void setLogName(String logName) { 
    this.logName = logName; 
  }

中介框架将调用处理程序的 handle() 方法。此方法将使用 shouldSendClone() 方法进行检查,以确定是否应克隆消息。如返回后的值为 true,则将使用 sendClone() 方法发送消息的一个克隆。修改生成的 handle() 方进,如清单 6 所示。

清单 6. 发送克隆的 handle() 方法

public boolean handle(MessageContext ctx) throws MessageContextException { 
    boolean contMsgProcessing = true; 
    SIMessageContext siCtx = (SIMessageContext) ctx; 
    if (shouldSendClone(siCtx)) { 
      sendClone(siCtx); 
    } 
    return contMsgProcessing; 
  }

如果应该克隆消息,则调用 shouldSendClone() 方法。首先将检查 CloneMessagePropertyName 属性以确保不会克隆已克隆的消息。然后我们将确保不在克隆消息的目标目的地上调用此中介。这两个检查将确保中介不会引发“消息风暴”(Message storm) 配置错误。将使用 getCloneMessagePropertyName(SIMessageContext ctx) 方法检查和上下文属性(如果已设置)。将清单 7 中所示的代码添加到该中介处理程序中:

清单 7. shouldSendClone(SIMessageContext) 的代码

private boolean shouldSendClone(SIMessageContext ctx) { 
    boolean sendClone = true; 
    SIMessage msg = ctx.getSIMessage(); 
    try { 
     Boolean clonedMsgProperty; 
      String clonePropName = getCloneMessagePropertyName(ctx); 
      clonedMsgProperty = (Boolean) msg.getUserProperty(clonePropName); 
      if ((clonedMsgProperty != null) && clonedMsgProperty.booleanValue()) { 
        sendClone = false; 
     } 
    } catch (Exception e) { 
      getLog().log(Level.SEVERE, "Exception getting message property: " + getCloneMessagePropertyName(ctx), e); 
    } 
    String mediationDest = ctx.getSession().getDestinationName(); 
    if (getCloneMessageDestination(ctx).equals(mediationDest)) { 
  sendClone = false; 
    } 
    return sendClone; 
  } 
  private String getCloneMessagePropertyName(SIMessageContext ctx) { 
    String value = (String) ctx.getProperty("cloneMessagePropertyName"); 
    if ((value == null) || (value.equals(""))) { 
      value = getCloneMessagePropertyName(); 
    } 
    return value 
  }

如果需要克隆消息,该处理程序将调用 sendClone() 方法,此方法负责克隆消息并将克隆消息发送到配置的目的地,然后将克隆消息路由路径的设置委托给 setRoutingPath(clone, ctx) 方法。后者也将设置一个消息属性,以指示消息为一个克隆消息。请将清单 8 所示的代码添加到该处理程序中:

清单 8. sendClone(SIMessageContext) 的代码

private void sendClone(SIMessageContext ctx) { 
    SIMediationSession session = ctx.getSession(); 
    SIMessage clone = null; 
    try { 
      clone = (SIMessage) ctx.getSIMessage().clone(); 
      setRoutingPath(clone, ctx); 
      clone.setUserProperty(getCloneMessagePropertyName(ctx), Boolean.TRUE); 
      session.send(clone, false); 
      getLog().log(Level.INFO, "Message {0} cloned and routed to {1}", 
             new Object[] { clone.getApiMessageId(), clone.getForwardRoutingPath() } ); 
    } catch (Exception e) { 
      getLog().log(Level.SEVERE, "An exception occurred sending the cloned message", e); 
    } 
  }

现在需要添加 setRoutingPath(SIMessage, SIMessageContext) 及其依赖性。setRoutingPath() method 将根据 ExistingRouteAction 属性修改所有现有路由路径。将清单 9 中所示的代码添加到该处理程序中:

清单 9. 设置克隆消息的路由路径

private void setRoutingPath(SIMessage clone, SIMessageContext ctx) { 
    List frp = clone.getForwardRoutingPath(); 
 String destName = getCloneMessageDestination(ctx); 
 SIDestinationAddress dest = SIDestinationAddressFactory.getInstance(). 
    createSIDestinationAddress(destName, false); 
    if ((frp.isEmpty()) || (getExistingRouteAction().equalsIgnoreCase("OVERWRITE"))) { 
      List newFrp = new ArrayList(1); 
      newFrp.add(dest); 
      clone.setForwardRoutingPath(newFrp); 
    } else { 
      if (getExistingRouteAction().equalsIgnoreCase("APPEND")) { 
        frp.add(dest); 
      } else { 
        frp.add(0, dest); 
      } 
      clone.setForwardRoutingPath(frp); 
    } 
  } 
  private String getCloneMessageDestination(SIMessageContext ctx) { 
    String value = (String) ctx.getProperty("cloneMessageDestination"); 
    if ((value == null) || (value.equals(""))) { 
      value = getCloneMessageDestination(); 
    } 
    return value; 
  }

现在就可以组装、部署和测试这个新的中介处理程序了。

组装、部署和测试发送克隆的中介

要组装中介,请按照如下步骤进行操作:

打开 DeployableMediationEJB 项目的部署描述符。

选择 Mediation Handlers 选项卡(图 7),然后使用 Add 按钮添加新的中介。
图 7. 添加发送克隆的中介
消息中介的实用介绍——第 2 部分:使用中介路由消息

保存部署描述符

如果服务器仍在运行,且已经部署了 DeployableMediation,则应当自动发布所做的更改。如果有必要,启动服务器并发布更改。

为了测试中介,需要定义一些消息传递资源。(下载文件中包含了一个管理脚本。)运行 sendCloneMediationAdmin.jacl 脚本以设置以下配置:

两个目的地,名为 messageQueue 和 clonedMsgQueue。

三个 JMS 资源,名为 jms/messageQueue、jms/clonedMsgQueue 和 jms/CF3。

一个名为 SendCloneMediaiton 的中介,将应用到 messageQueue。

重新启动服务器,启动 UTC,然后向 jms/messageQueue 发送一条测试消息。如果成功调用中介处理程序,所得的结果将为一个设置到 clonedMsgQueue 目的地的克隆消息。通过检查服务器日志项或通过使用管理控制台浏览两个队列点,可以对此进行验证。应当看到一个如下所示的项(此消息将在单个行上显示):

[17/04/05 15:54:00:912 BST] 0000005e MsgMediaiton I Message ID: 
  ee5d090dc9dc751359fe3936110a134f0000000000000001 cloned and sent to [[ clonedMsgQueue, false, null, ]] 

结束语

本文的目的是演示如何使用中介处理程序进行消息路由。首先我们了解了如何修改消息的路由,以使其可以发送到不同的目的地。随后,我们了解了如何开发中介处理程序以将消息从一个目的地复制到另一个目的地。通过这些示例,您将获得更多组装、部署、测试中介和基于消息的解决方案的经验。

本系列的下一篇文章将讨论访问消息负载,以便可以根据消息的内容对消息进行处理。我们将扩展 DebugMediation 以输出消息内容,并开发一个修改消息内容的简单中介。

本文示例源代码或素材下载

Tags:消息 中介 实用

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接