既然我们已经讨论了如何建立总线以及如何将 JMS 作为整个总线的消息协议,最后我们准备将另一个关键组件引入我们的解决方案中,这就是中介!
在使用 IBM WebSphere Application Server 中的新消息引擎构建企业服务总线 (ESB) 系列的第 4 部分中,我们将说明如何向正在构建的解决方案添加一个简单的中介来访问流经总线的消息。
到目前为止,我们的解决方案已在下列文章中得到发展:
如第 1 部分所述,发送到总线的消息实际上流向目的地。可以通过配置将目的地彼此链接在一起,从而有效地创建消息遵循的路由路径。
中介可以在消息从一个目的地流向另一个目的地时访问它们。一个中介可以与一个或多个目的地相关,而且在消息到达该目的地时立即被调用。调用后,中介就可以访问消息及其流经目的地的上下文,而且可以更改消息的内容和消息的路由(即消息发送到的下一个目的地),还可以将消息写入日志并监控流经总线的数据,这是 ESB 提供的核心特性之一。
稍后,我们将在示例中利用中介的另一个概念,即中介可以使用所谓的上下文属性读取配置信息,这些属性是通过应用服务器管理控制台配置的键值对。可以利用这种特性来提供 Switches,Switches 能够在不更改中介的代码的情况下改变其行为。
要了解中介的基础知识,请参阅 消息中介的实践介绍。
可以将中介编写成与协议无关,并且将任何协议(即 SOAP、JMS 或者 MQ)处理分隔到独立的中介处理程序中是一个好的设计习惯。也就是说,一个中介可以独立于用来将消息发送到相关目的地的协议。这需要中介以中立方式访问消息数据。而这正是服务数据对象(Service Data Objects,SDO)的用武之地。我们在此不对 SDO 予以详细说明(请参阅参考资料以获取更多信息),但是请注意,只要出于高级目的开发中介,您就需要利用 SDO API。
在中介编程的核心,每个中介都实现一个名为 MediationHandler 的通用接口,该接口允许在将消息传递到目的地时由总线对其进行调用。该接口中的唯一方法称为 handle(),它带有一个 MessageContext 类型的参数。除了其他内容之外,此上下文还包含一个对实际消息的引用。这几乎是该接口的全部内容!当消息到达时调用 handle() 方法,然后通过 MessageContext 参数将消息传递给中介。
顺便说一下,如果您熟悉 JAX-RPC 处理程序的概念,则中介的编程模型与之非常相似(但并不相同!)。事实上,中介所使用的 MessageContext 类来源于 JAX-RPC 规范。
然而,如何实际开发和安装中介呢?不要着急,我们马上就要向您展示一个简单的循序渐进示例。
在我们的示例中,将开发一个中介来记录发送到目的地的每条消息。该消息只打印到 System.out。实际的解决方案很可能利用标准 java.util.logging 机制。现在,我们将不对实际消息内容进行更改,而把它留到另一篇文章中介绍。
WebSphere Application Server Toolkit (AST) 或 IBM Rational® Application Developer for WebSphere Software V6(以下简称为 Application Developer)可以用于为 WebSphere Application Server 开发代码和创建包含中介的的可安装包。一个重要的细节是,中介——即使它们是作为简单的 Java™ 类开发的——是以无状态会话 EJB 组件的形式部署的。AST 或 Application Developer 将在部署中介时生成该 EJB。稍后做详细说明。
要开发中介,请执行下列步骤:
- 在您选择使用的开发工具中创建一个新的 EJB 项目,并将其命名为
LoggingMediation。 - 缺省情况下,该工具还会提出创建一个新的 EAR 项目(名为 LoggingMediationEAR)。我们将使用此缺省名称。
- 在 EJB 项目的预定义 ejbModule 文件夹中创建一个称为
logging的包(假定您在该工具的 J2EE 透视图中)。 - 最后,在这个称为
LoggingMediation的包中创建一个新的 Java 类,该类实现 com.ibm.websphere.sib.mediation.handler.MediationHandler 接口。图 1 显示了此结构。
图 1. EJB 项目结构
该工具还将为您创建一个空实现类,此类在一个具有签名的空方法中包含以下代码:
public boolean handle(MessageContext arg0) throws MessageContextException {
- 将以下代码添加到 handle() 方法中,该方法将记录消息的接收。
public boolean handle(MessageContext arg0) throws MessageContextException { // Convert the MessageContext into an SIMessageContext SIMessageContext sim = (SIMessageContext)arg0; // Retrieve the message from the context SIMessage message = sim.getSIMessage(); try { if (message.getFormat().equals("JMS:text")) { // get an SDO DataGraph from the message DataGraph dataGraph = message.getDataGraph(); //SIBus SDO representation of a JMS message, has a property named 'data' DataObject jmsMessage = root.getDataObject("data"); //the DataObject for the JMS message has a property which contains the //value of the message. We access that value as a string. SDO will do //its best to convert the message in the format requested. String payLoad = jmsMessage.getString("value"); System.out.println("Message logged. The payload of the message is "+payLoad); } else { System.out.println("The received message is not a JMS text message!"); } } catch (SIException ex) { System.out.println(ex.getLocalizedMessage()); } return true; }
- 将下列导入语句添加到该类中:
import com.ibm.websphere.sib.mediation.handler.MediationHandler; import com.ibm.websphere.sib.mediation.handler.MessageContextException; import com.ibm.websphere.sib.mediation.messagecontext.SIMessageContext; import commonj.sdo.DataGraph;
请注意如何检索消息的负载。系统集成总线 (SIBus) 使用服务数据对象(Service Data Objects,SDO)的动态接口。消息以 SDO DataGraph 的形式呈现,因此我们调用名为 getDataGraph() 的方法。DataGraph 始终至少包含一个 DataObject 实例——即实际数据。一旦我们从图中获得根 DataObject,就可以使用 getRootObject() 方法来查看它的属性。
JMS 消息的 SIBus 表示在根 DataObject(它返回另一个 DataObject)上定义一个名为 data 的属性。此数据 DataObject 具有一个名为 value 的属性,它就是实际消息内容。
方法 getString("value") 是 SDO 动态接口的组成部分,需要对其进行一点说明。我们可以检索符合我们要求的任何类型的属性;对 DataObject 的 SDO 调用将尽量转换属性类型——只要它不是以该类型存储在 DataObject 中。然后,在我们的示例中使用 getString() 方法,这表示我们希望所检索属性的内容是字符串形式的。在 DataObject (...) 中,还有一些其他的方法尝试以各自的类型返回属性的内容。
对于高级中介编程来说,我们在此所做的关于 SDO 处理的说明当然是不够的。请参阅参考资料,以获得更全面的关于 SDO 和如何将其应用于 WebSphere Messaging Resources 的讨论。
我们究竟如何知道像 data 和 valu 这样的属性存在并且它们确实是我们所要查找的?WebSphere Application Server V6 Information Center 中对此进行了说明;在 SDO Datagraph information => JMS Formats 下进行搜索并查看任何格式。
为了确保此中介仅用于 JMS 文本消息,我们添加了对 message.getFormat() 的调用,这将返回该消息类型的字符串 JMS:text。在实际的解决方案中,我们要么创建一个中介来处理所有的消息格式,要么为每种消息格式开发一种日志记录中介。
现在,我们可以部署我们的中介了。这意味着我们向 EJB 项目的 EJB 部署描述符中添加一个名为 LoggingMediation 的条目。该工具将自动生成一个无状态会话 Bean 来包装我们刚刚创建的中介。部署描述符中的这一新条目不是标准 EJB 2.1 部署描述符的组成部分,因此它存储在扩展文件 ws-handler.xmi 中。然而,该工具允许我们在一个编辑器窗口中编辑标准字段和所有扩展。
要部署新的中介,请执行下列步骤:
- 在 Project Explorer 视图中,双击 Deployment Descriptor: LoggingMediation 条目。这将在编辑器窗口中打开部署描述符(仍然为空)。
- 选择底部的 Mediation Handlers 选项卡来定义中介(图 2)。
图 2. 中介处理程序参数
- 要添加新的中介,请选择 Add... 按钮。
- 在 Define Mediation Handler 窗口中,选择 Browse 按钮,以定位到我们的中介类(图 3)。
图 3. 定义新的中介
- 选择 OK。
- 在 Name 字段中输入
LoggingMediation,然后单击 Finish。 - 在完成这一步后,您应该看到模块中有一个新的 Session EJB,它表示中介(图 4)。
图 4. 项目中定义的中介
现在,我们可以将包含中介的 EAR 项目安装到应用服务器中。
要安装新的中介,请执行下列步骤:
- 使用开发工具中的 Export 菜单选项将 LoggingMediationEAR 项目导出到 EAR 文件中。(请参见下载,以获得完整的 loggingmediation.ear 文件)。
- 启动应用服务器并在浏览器中打开管理控制台。
- 从 loggingmediation.ear 文件安装新的企业应用程序。在安装的过程中,记住同时选中 Generate default bindings 和 Deploy enterprise beans 复选框(如果它们尚未选中)。所有其他字段均保留缺省值。
- 安装完成后,请转到管理控制台的 Enterprise Applications 视图,并启动新的 LoggingMediationEAR 应用程序。
接下来,我们将中介定义到总线:
- 打开总线的管理视图,我们称之为 TheBus,然后选择 Mediations(图 5)。
图 5. 总线配置属性
- 选择 New。
- 在 Mediation name 和 Handler list name 字段中,均输入值
LoggingMediation,如图 6 所示。
图 6. 配置总线中介
- 选择 OK 保存更改。现在,您拥有了一个可以与任何目的地关联的中介。
于是我们可以测试新的中介,我们将把它与之前在 JMS 示例中用到的 PackageReceivedDestination 目的地关联起来:
- 在管理控制台中打开目的地列表并检查 PackageReceivedDestination。
- 选择 Mediate 按钮,如图 7 所示。
图 7. 将目的地与中介相关联
- 在图 8 中显示的对话框中,确保选择了 LoggingMediation 中介(它应该是定义的唯一中介),然后选择 Next。
- 再次选择 Next,然后选择 Finish。
- 保存您的更改。目的地列表现在显示 LoggingMediation 被分配给 PackageReceivedDestination(图 8)。
图 8. 将目的地与中介相关联
您可以只运行 JMS 客户机应用程序来测试中介,如本系列文章的第 3 部分所述,假定您已经安装并启动了 PackageReceived 企业应用程序(请参阅参考资料以获得包含此 EAR 文件的文章)。使用 launchclient 工具启动客户机应用程序。logs\server1 目录下的 System.out 文件现在包含来自中介的其他输出(图 9)。
图 9. 包含中介输出的日志文件
在图 9 中,看起来输出似乎记录了两次。之所以出现这种情况,是因为消息内容首先由中介记录,然后由接收 MDB 记录。
在本系列关于使用 WebSphere Application Server V6 构建企业服务总线的的第 4 部分中,我们已经演示了如何开发、部署和安装中介,以及如何配置 ESB 来使用中介,这是新的 WebSphere Messaging Resources 的核心概念。作为简单 JavaBeans 开发的中介包装到一个无状态会话 EJB,并作为企业应用程序安装在应用服务器中,而且在其与一个目的地相关联后,只要消息到达目的地,就会被激活。由于本来就具有灵活性,所以中介可以转换和路由消息,或者仅用于日志记录目的,正如本文所述。
| 名字 | 大小 | 下载方法 |
|---|---|---|
| LoggingMediationEAR.ZIP | 5 KB | FTP |
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
-
利用 WebSphere 应用程序服务器 V6 创建企业服务总线:第一部分,WebSphere V6 消息资源介绍
-
利用 WebSphere 应用程序服务器 V6 创建企业服务总线:第二部分,业务需求和总线
-
利用 WebSphere 应用程序服务器 V6 创建企业服务总线:第三部分,一个简单的 JMS 消息实例
-
消息中介的实践介绍
-
Patterns: Service-Oriented Architecture and Web Services
-
Patterns: Implementing an SOA using an Enterprise Service Bus
-
Service Data Objects 介绍
-
Recorded presentation on Meditions
- 通过参与
developerWorks 博客进入 developerWorks 社区。
- 购买打折的 Web 服务书籍。