使用JMS和ESB构建强大而可靠的SOA(三)

日期: 2009-02-08 来源:TechTarget中国 英文

  引言

  在第1部分中,我们介绍了企业服务总线(ESB)的概念,在第2部分中,我们演示了如何建立测试应用程序客户端和提供程序。本系列中的三篇文章介绍了如何通过JMS和IBM WebSphere ESB建立服务提供者和使用者之间的连接,在最后这篇文章中,我们将研究如何使用带有自定义JMS绑定的中介流组件来最终建立连接。

  如果您还记得第1部分,我们曾讨论过构成WebSphere ESB基础的编程模型,即服务组件体系结构(SCA)。在这个体系结构中,不同类型的组件都被看作服务,并且可使用相同的方式进行访问。WebSphere ESB中介流是这些组件类型中的一种。与任何SCA组件一样,可以通过中介流所提供的导出对其进行访问,并且中介流可以通过导入将消息转发到其他的外部服务。JMS的特殊类型的导入和导出,称为JMS绑定,允许用户指定绑定配置并编写自己的数据处理代码。中介流本身包含一系列的中介基元,在消息通过总线时,可以使用这些中介基元对消息进行相应的操作。

  另外两篇developerWorks文章Getting started with WebSphere Enterprise Service Bus and WebSphere Integration Developer和Developing custom mediations for WebSphere Enterprise Service Bus将向您介绍创建中介模块的基本场景。在继续学习本文之前,最好先阅读(或至少是浏览)这些文章。

  概括地说,最后的这篇文章将:

  介绍如何为JMS绑定编写处理各种JMS消息类型的数据处理插件。
  说明如何建立充分利用自定义绑定代码的导出和导入。
  描述使用WebSphere Integration Developer的一个简单中介流的实现。

  将所有的内容组合到一个中介模块中,您可以将这个中介模块部署到WebSphere ESB运行时,并且这将允许您运行整个应用程序。

  下载部分中包含了完整的项目交换ZIP文件, 您可以将它导入到WebSphere Integration Developer,并且其中包含了所有的代码和运行该示例所需的其他内容。为了节省时间,并使得我们可以把主要精力放在接下来的主题,请在继续学习本文 前下载并导入这个文件。本文余下的内容假设您已完成了这项操作。在描述该解决方案中的各个部分时,我们将说明在导入了该文件后,每个部分位于WebSphere Integration Developer中的何处。

  JMS自定义绑定

  在为导入或导出创建JMS绑定时,您需要确定用来处理传入和传出消息的两个Java类。一个类称为函数选择器,另一个类称为 数据绑定。我们还需要定义用于入站和出站JMS流量的JMS队列的名称。让我们更仔细地看看这些部分。

  函数选择器

  与所有的SCA服务组件一样,WebSphere ESB中介具有一个接口。在WebSphere ESB中,将该接口表示为WSDL PortType,这意味着每个中介流组件支持一项或多项操作(或方法,在此上下文中,这两个术语表示相同的含义)。然而,JMS消息仅包含数据,而不包含它想要进行的任何目标操作的指示。所以,我们需要将特定的JMS消息映射到目标服务接口的特定操作。这正是函数选择器所完成的工作。

  在我们的示例中,我们已经为每个JMS消息类型(可在JMSCustomBindingLibrary/JMSCustomBindingInterface.wsdl中找到)定义了具有一项操作的服务接口。例如,应该将JMS文本消息发送到handleText()操作,而将流消息发送到handleStream()操作等等。稍后您将看到,我们可以为不同的操作指定不同的数据绑定。

  清单1显示了我们的示例中函数选择器的代码段:

  清单1. 函数选择器代码段

  public class SimpleJMSFunctionSelector implements FunctionSelector { public String generateEISFunctionName(Object[] arguments) { … … Message message = (javax.jms.Message) arguments[0]; functionName = message.getJMSType(); if (functionName == null) {  if (message instanceof BytesMessage)   messageBodyType = “Bytes”;  else {   if (message instanceof TextMessage)}    messageBodyType = “Text”; … … functionName = “handle” + messageBodyType; … …}

  请注意generateEISFunctionName()方法如何返回关联于指定消息的函数(或操作,或方法)的名称。在我们的示例中,函数名称为“handle”加上该消息类型。例如,对于JMS文本消息,将返回“handleText”。换句话说,当中介接收到一个JMS文本消息时,会将它发送到handleText()方法。

  在导出的绑定属性中,在Connection选项卡的高级设置下,对函数选择器进行了定义,如图1所示。

               

  图1. 在WebSphere Integration Developer中对函数选择器进行设置

  WebSphere Integration Developer还提供了一个缺省的函数选择器,称为com.ibm.websphere.sca.jms.selector.impl.JMSFunctionSelectorImpl,它从传入的JMS消息的Header属性TargetFunctionName处获取指定的字符串值作为函数的名称。

  数据绑定

  数据绑定的实现是JMS自定义绑定的关键部分。在导出绑定的情况下,这个数据绑定实现必须清楚每个传入消息的格式和结构,并将其转换为适合于该中介流的格式,即SDO DataObject。在导入绑定的情况下,则进行相反的处理,也就是说,将传出的SDO DataObject转换为发送到外部服务的JMS消息。

  SCA要求每个服务组件都具有一个接口,该接口可以是一个Java接口,或者描述为WSDL portType(WebSphere ESB MediationFlow组件支持WSDL接口)。要接收任意的JMS消息作为中介流中的成员,我们必须定义表示这些消息的一组操作。例如,JMS文本消息由下面的WSDL portType操作来表示:

  清单2. JMS文本消息的portType操作

  p<wsdl:portType name=”JMSCustomBindingInterface”>  <wsdl:operation name=”handleText”>      <wsdl:input message=”wsdl1:JMSTextMessage”/>      <wsdl:output message=”wsdl1:JMSTextMessage”/>      <wsdl:fault message=”wsdl1:JMSTextMessage” name=”TextFault”/>  </wsdl:operation>… …</wsdl:portType>

  在为导出或导入绑定定义了该接口之后,您需要提供处理DataObject和JMS之间转换的数据绑定类。它可以是针对整个导出/导入的一个类,或者每个操作一个类。我们已经在接口中定义了几项操作(每个JMS消息类型一项操作),因此我们定义了方法级的数据绑定,如图2所示。

                   

  图2. 方法级数据绑定定义

  每个数据绑定类都必须实现com.ibm.websphere.sca.jms.data.JMSDataBinding接口。

  在我们的测试应用程序中,共有5个JMSDataBinding实现:

  JMSTextDataBinding
  JMSBytesDataBinding
  JMSStreamDataBinding
  JMSMapDataBinding
  JMSObjectDataBinding.

  您可以在JMSCustomBindingClasses项目中找到它们的源文件和其他的实用工具类。

  一个数据绑定实现必须提供对下列方法的实现:

  setDataObject()设置表示JMS消息有效负载的DataObject的值。DataObject必须符合相应的模式定义。
  getDataObject()返回表示JMS消息有效负载的DataObject,并且该对象符合相应的模式。
  getMessageType()返回JMS消息的类型(在JMSDataBinding接口中定义)。
  read(Message message)根据JMS消息设置DataObject属性的值,JMS消息作为方法参数提供。
  write(Message message)根据DataObject的属性设置JMS消息有效负载的值,JMS消息作为方法参数提供。
  isBusinessException()表示是否将该JMSDataBinding实例所表示的DataObject作为一项业务异常。
  setBusinessException()设置是否将该JMSDataBinding实例所表示的DataObject作为一项业务异常。

                   

  图3. 带JMS绑定的SCA导入/导出的方法执行流

  在图3中,当JMS消息发送到该中介模块(即导出)时发生JMS–>SDO流,而在该中介模块(即导入)发送JMS消息时发生SDO–>JMS流。请注意,带JMS绑定的导入的响应消息并没有经过函数选择器。

  清单3显示了com.ibm.websphere.sibx.samp.jms.JMSTextDataBinding类的部分源代码,该类对所有传入和传出的JMS文本消息进行处理。

  清单3. JMSTextBinding代码示例

  public class JMSTextDataBinding extends AbstractJMSDataBindingImpl                                 implements JMSDataBinding {private String payload = null;private DataObject jmsData = null;public int getMessageType() { return JMSDataBinding.TEXT_MESSAGE;}public void read(Message message) throws JMSException {… …TextMessage textMessage = (TextMessage) message; payload = textMessage.getText();… …// construct a DataObject based on the schema definition for // “JMSTextMessage” jmsData = DataFactory.INSTANCE.create(“com.ibm.ws.sib.mfp/schema”,”JMSTextBody”);… … // set the “value” property to the String value of the message payload jmsData.setString(“value”, payload);… …} public void write(Message message) throws JMSException {… …TextMessage textMessage = (TextMessage) message;// Clears the body of the JMS messagetextMessage.clearBody(); // Sets the value of the JMS message payload from the DataObject’s // ‘value’ property payload = jmsData.getString(“value”); textMessage.setText(payload);… …}public DataObject getDataObject() throws DataBindingException { return jmsData;}public void setDataObject(DataObject jmsData) throws DataBindingException {this.jmsData = jmsData;}}

  read()方法将JMS TextMessage转换为数据对象,而write()方法将数据对象重新转换为JMS TextMessage。在read()方法中,使用相应的模式创建了一个新的数据对象,在部署该中介模块的过程中,WebSphere ESB运行时可以使用该数据对象。在write()方法中,代码读取了数据对象的内容,并将其存储在传递的“message”参数中。通过getMessagetype()方法来确定消息的类型。

  使用下面的一行代码来读取DataObject的有效负载:

  payload=jmsData.getString(“value”);

  这段代码使用了标准的SDO API调用。检索属性的名称为“value”,来源于JMSTextBody的模式定义(在JMSCustomBindingLibrary/JMSBodyModels.xsd文件中):

  清单4.

  <xsd:complexType name=”JMSTextBody”>         <xsd:sequence>            <xsd:element name=”value” type=”xsd:string”/>          </xsd:sequence>  </xsd:complexType

  在该中介的WSDL接口中引用JMSTextBody类型。清单2中的portType消息指向这个模式。换句话说,该中介的接口定义了数据绑定类必须处理的SDO的结构。因此,任何JMS自定义数据绑定实现都与关联于中介流组件接口的模式密切相关!

  其他JMS消息类型的数据绑定类也是类似的。我们将把对这些类的分析工作留给您完成。此外,每个数据绑定实现都与JMSBodyModels.xsd文件中给出的相应模式定义密切相关。JMSStreamDataBinding和JMSMapDataBinding类稍微复杂一点,因为它们需要保留流或映射中每个单独的元素的类型信息。有关更详细的信息,请查看JMSBodyModels.xsd文件中的复杂类型定义。

  所有自定义JMS数据绑定都具有一个称为AbstractJMSDataBindingImpl的公共超类,这个类实现了一些公共的功能,比如,进行异常处理的方法。

  JMSDataBindingLogger类负责进行日志记录。要在自定义绑定代码中激活日志记录,可以将WebSphere ESB运行时中的Trace details设置为com.ibm.websphere.sibx.samp.jms.*=fine。

  JMS参数

  完成JMS自定义绑定定义的最后一步是为传入和传出的流量选择合适的JMS资源。

  在绑定属性中,还定义了所需的JMS队列目标和连接工厂引用。如下面的图中所示,JMS导出绑定组件的连接工厂的定义位于JMS Export Binding选项卡的高级设置下面:

             

  图4. JMS导出绑定的连接工厂引用定义

  队列目标引用的定义位于JMS Destinations选项卡下面:

                 

  图5. JMS导出绑定的队列目标引用定义

  我们没有给出导入绑定组件相应的屏幕截图,因为除了可以在JMS Import Binding选项卡下面找到连接工厂定义之外,它们基本上都是相同的。在您导入本文中的项目交换文件时,所有这些值都应该已经设置好了。

  中介流

  在为导出和导入编写了自定义绑定代码之后,我们可以开始将注意力集中到中介流组件本身。在WebSphere Integration Developer Assembly Editor中,打开JMSCustomBindingMediationModule,然后双击JMSCustomBindingMediationComponent1以打开Mediation Flow Editor。在这个编辑器中,流组件接口的每项操作都表示为一个请求和一个响应流(图6)。

              

  图6. Mediation Flow Editor

  这些流完全与导入和导出中所使用的那些绑定独立。实际上,这正是在流实现之外将其转换为一个SDO DataObject实例的原因:无需知道发送到该中介模块的和该中介模块发送的消息的协议和格式,就可以构建这些流。

  在这里,我们只将其中的一个流作为示例进行详细描述,即JMS TextMessage流,因为这是最常见的JMS消息类型。我们还为这个消息类型的响应流添加了一些特定的异常处理机制。(其他消息类型的流也都是非常相似的。)

  让我们一步一步地描述该中介模块对JMS TextMessage的处理:

  当客户端向中介模块发送JMS TextMessage时,中介模块将这个消息放到JMS导出绑定组件的接收队列目标中。因为这个导出组件作为JMS自定义绑定实现,所以由自定义的函数选择器对该消息进行处理。如上所述,根据传入消息的类型,选择器返回函数名称“handleText”。
  由于导出组件采用方法级数据绑定定义(如图2所示),所以选择了JMSTextDataBinding类来处理数据转换。这个类提取了传入的JMS TextMessage的文本有效负载,并且创建了遵循适当的XML数据类型(即JMSTextBody)的SDO DataObject实例。将DataObject中的“value”字符串属性设置为JMS TextMessage的有效负载的值。

  然后将这个新的DataObject传递给中介流组件。因为将它传递给了handleText操作,所以这个流处理的消息正是当您在Mediation Flow Editor中选择handleText链接时所看到的那个消息(请参见图6)。

  使用MessageLogger中介基元在请求流中记录下这个消息。

  当这个消息离开请求流时,它进入在Mediation Flow Editor中由JMSCustomBindingPartnerInterface表示的JMS导入绑定组件。在这里,将DataObject重新转换为JMS TextMessage,并且最终发送到导入组件的发送队列目标。

  服务提供者(在我们的测试应用 程序中是消息驱动的Bean)监听这个队列目标上的消息。它的onMessage()方法仅打印出接收到的消息的内容。其中添加了一些特殊的代码,以模拟异常处理过程:如果文本消息的内容为“exception”,那么将该响应JMS TextMessage中称为IsBusinessException的Header属性设置为“true”。

  现在,将响应JMS TextMessage发送回该中介模块,并将对其进行和前面一样的处理:JMS导入绑定组件将其转换为SDO DataObject。如果传入IsBusinessException属性设置为“true”的TextMessage,那么通过错误调出  而不是正常的响应调出  将它传递给响应流。

  如图6所示,在响应流中,如果通过错误调出输入消息,那么仅对这个消息进行记录(通过MessageLogger3),并将其转发到错误输入。 在所有其他的情况下,消息将通过一个称为BusinessExceptionCustomMediation的自定义中介元素,我们在这个中介元素中添加了相应的逻辑,以便在文本消息的内容为“Error”时生成另一个异常。在这种情况下,该消息将流过自定义中 介元素的失败终端,并对其进行记录,然后再次被转发到错误输入。

  对于所有“正常”消息(即没有执行异常处理的消息),仅对其进行记录,并转发到输入终端 。

  最后,将到达JMS导出组件的响应DataObject重新转换为JMS TextMessage,并将其放到发送队列目标。这样,任何JMS客户端都可以对其进行检索。如果导出组件通过中介流的错误输入接收到响应消息,那么它不仅将执行正常的数据转换,还将为生成的JMS TextMessage添加一个名为IsBusinessException的Header。客户端可以使用它来确认在消息处理的过程中是否发生了异常。

  将其组合到一起

  既然我们已经完成了导出和导入绑定的定义,并且提供了中介流的实现,那么我们就可以最终部署并运行整个示例了。在第2部分中,我们向您介绍了如何安装和部署测试应用程序客户端和测试提供程序。还需要进行安装的就只有该中介模块了。

  有两种方法可以将中介模块安装到WebSphere ESB运行时服务器:

  使用WebSphere Integration Developer WebSphere ESB测试环境:
  在WebSphere Integration Developer中,打开Servers视图,请确保创建并启动了WebSphere ESB Server v6。

  右键单击该服务器并从上下文菜单中选择Add and remove projects… 。

  在接下来的对话框中,选择JMSCustomBindingMediationModuleApp项目,并将它添加到服务器。

  使用WebSphere ESB管理控制台:

  在WebSphere Integration Developer中,切换到J2EE Perspective并选择Enterprise Applications下的JMSCustomBindingMediationModuleApp。
  将该项目导出到一个EAR文件。
  打开Servers视图,右键单击WebSphere ESB Server v6并从上下文菜单中选择Run administrative console。
  在管理控制台中,通过Applications=>Install New Application将导出的EAR安装到运行时中。

  要测试该应用程序,可以打开一个Web浏览器,然后浏览至http://:/JMSTestClientWeb/index.html(和取决于您本地的服务器配置,通常可以使用“localhost”和端口9080)。请按照第2部分中给出的说明来发送不同类型的JMS消息,然后选择Click here to select messages on the reply queue以查看响应消息。其屏幕显示应该与图7所示类似。

                

  图7. 成功发送一个TextMessage后JMSTestClient的结果Web页面

  结束语

  在本文中,我们通过一个具体的示例向您介绍了如何在WebSphere ESB中为中介流组件构建JMS自定义绑定。我们讨论了处理传入和传出的JMS消息所必需的数据绑定和函数选择器代码,以及导出和导入所需的绑定属性。我们了解了如何以可视化的方式构建中介流组件,最重要的是,独立于与中介流进行通 信的过程中使用的协议。

  我们以这篇文章结束了关于这个主题的系列文章。请继续阅读更多关于WebSphere ESB的文章,以及如何使用它及其相应的工具WebSphere Integration Developer来构建高级的解决方案!

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

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

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

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐

  • 掌握基础的Java信息传送理念

    我们正步入应用程序组件化飞速发展的时代,在这个时代,即使是云也布满组件化。因此,开发人员应该思考如何设计出超越初期Java信息传送的JMS。

  • 开源和企业服务总线(ESB)

    最近几年中,企业服务总线(ESB)已经在许多SOA程序中固化了。你可以说你在做SOA 而不能说已经完成了ESB。但是很可能成功的SOA……

  • VMware/SpringSource收购RabbitMQ

    VMware旗下SpringSource宣布收购Rabbit科技,Rabbit是一家来自英国的开源公司,主要经营企业消息软件。SpringSource表示该公司的旗舰产品RabbitMQ……

  • 解析SOA十大设计原则

    通过跨越定义明确的边界进行显式消息传递,服务得以彼此交互。有时候,跨越服务边界可能要耗费很大的成本,这要视地理、信任或执行因素而定。