|
|
简介 实现异步互用性是第 1 章“简介”中所介绍的第三个互用性场景,其中包括从 .NET Framework 组件到数据层中消息队列组件的连接。异步互用性包括希望客户端应用程序能够调用另一个层或进程的情况。通过调用,客户端可在远程组件处理请求的同时继续进行操作,而不是等待结果。 使用异步操作只对针对这种操作样式的任务有意义。在 XBikes 应用程序示例中,订单处理是使用消息队列的较好范例,并且推荐为适用于消费者电子商务应用程序业务的最佳做法。 本章主要关注于到 IBM WebSphere MQ 的连接。另一节描述了 Microsoft Host Integration Server (HIS) 附带的 MSMQ-MQSeries 桥,并在 Microsoft 消息队列 (MSMQ) 和 IBM WebSphere MQ (通常称为 MQSeries)之间提供桥接。 有关 JNBridgePro 的小节中描述了如何生成桥接 .NET Framework 业务层组件和 WebSphere MQ 间连接的 Java 代理程序集。本章的最后部分使用 Ja.NET 来展示相同的技术。 确定数据交换格式和数据类型 如同使用其它互用性技术一样,首先必须确定 .NET Framework 和 Java 都可接受的数据格式。该选择取决于以下因素: • 如何与消息队列集成? • 使用桥接产品来包装消息队列功能吗? • 使用 MSMQ-MQSeries 桥吗? 数据交换格式和数据类型的选择取决于使用的互用性集成技术: • 如果使用其中一种桥接产品来包装消息队列功能,则可能需要使用与点对点通讯中所用相同的数据交换格式和数据类型。 • 如果使用 MSMQ-MQSeries 桥,则必须执行与 Web 服务相似的策略。为了允许从消息队列读取对象和向其写入对象,必须将这些 XML 文档序列化成字符串。XML 格式的字符串可保留 .NET Framework 或 Java 对象中包含的丰富信息,并能够克服交换实际对象时出现的互用性难题。 本章就这些选项分别进行了说明。 设计和构建服务接口 将消息队列用于异步互用性时,不能跨越技术边界直接调用服务接口。服务接口的角色更像“消息使用者”。该服务接口是一个应用程序,负责监视并从队列获取消息、打开数据包并将其发送到现有的外观或处理该消息的应用程序。 .NET Framework 和 J2EE 都提供从消息(.NET Framework 中的队列组件和 J2EE 中由消息驱动的 bean)激活组件的内建支持。然而,每种情况就所需消息的结构各有不同,因此在 .NET Framework 和 J2EE 间需要互用性时,该方法不可行。可自己编写服务接口以使用消息,并将它们传递给合适的服务外观。 建立消息使用者非常容易。无论使用哪种技术编写该消息,使用消息的技术是相同的。需要创建客户端应用程序或服务来轮询队列上的消息并读取所有找到的消息。从消息中提取的数据或者已经是以正确格式(如果它使用的是桥接技术)表示,或者需要用第 7 和第 8 章所述的 Web 服务技术从 XML 字符串反序列化为正确的数据类。 图 9.1 显示了异步通讯中服务接口的角色。  图" 9.1:异步通讯中服务接口的角色 将数据返回到正确格式后,需要做的就是对适当的服务外观进行方法调用。 设计和构建异步互用性适配器 构建异步互用性适配器类似于构建同步适配器,除了将消息放入消息队列中,而不是调用正确的服务接口。此外,根据使用的技术,可能必须操作数据,将其转化成 Java 数据代理或序列化为 XML 字符串。 图 9.2 显示了异步通讯中互用性适配器的角色。  图" 9.2:异步通讯中互用性适配器的角色 消息加入消息队列的方式取决于所用的技术。对于包装 JMS 功能的桥接产品,可以使用 ObjectMessage 类型将消息放入队列中,否则必须使用基于文本的消息类型。 使用 MSMQ-MQSeries 桥 如果熟悉从 .NET Framework 写入 MSMQ 的消息代码,并且具有编写 JMS 代码以使用 WebSphere MQ 的经验,则使用 MSMQ-MQSeries 桥来实现互用性比较简便。 MSMQ-MQSeries 桥要求两台计算机,第一台的配置如下: • Windows 2000 或 Windows 2003 • Active Directory • MSMQ-MQSeries Bridge • MSMQ (带路由支持) • WebSphere MQ 客户端 第二台计算机应该安装 Windows 2000,作为成员服务器并运行 WebSphere MQ。 需要将运行 WebSphere MQ 的计算机配置为 MSMQ 中的外部计算机。通过在 Active Directory 站点和服务中的 Services/MsmqServices 节点下创建外部站点来完成此任务,添加新的 MSMQ 路由链接以将本地站点(通常为默认的第一个站点的名称)链接到外部站点,添加该 MSMQ 计算机作为本地站点网关,然后添加 MQ Series 计算机作为到外部站点的外部计算机。 有关配置 MSMQ 外部站点的详细信息,请参阅 TechNet 上的“Configuring cross-platform messaging”。 有关配置和使用 MSMQ-MQSeries 桥的详细信息,请参阅 TechNet 上的“Chapter 13 MSMQ-MQSeries Bridge Configuration Guide”。 考虑使用 JMS 读取 WebSphere MQ 消息的情况。最初,这些消息来自 MSMQ 并通过桥接传递。在本例中,如果更改 WebSphere MQ JMS 配置,应该不会出现消息使用问题。为了实现这个互用性场景,将 WebSphere MQ 的 targetClient 队列配置设置为 MQ,而不是 JMS。如果不做此更改,则 WebSphere MQ 会预期获得 .NET Framework 无法生成的 JMS 头消息。 注 在现有队列上不要配置 targetClient,因为更改可能会导致现有 JMS 应用程序失败。始终为互用性创建专用的新消息队列。 反之,如果将 targetClient 更改为 MQ,则可从 JMS 生成消息,随后通过桥接传递它们并在 .NET Framework 应用程序中进行使用。 配置消息队列 为了通过 MSMQ-MQSeries 桥实现互用性,需要为消息发送的每个方向创建两个队列。需要为接收消息定义本地队列以及为发送消息定义远程队列。还必须正确配置桥接。 图 9.3 显示了如何在 .NET Framework 和 Java 间希望发送消息的每个方向上设置两个队列。  图" 9.3:连接 MSMQ 和 MQ Series 的 MSMQ-MQSeries 桥的逻辑表示 从定义 MSMQ 队列开始。向运行桥接的计算机添加本地队列,向外部计算机添加远程队列。 其次,使用 MSMQ-MQSeries 桥管理器,添加指向运行 WebSphere MQ 的计算机的 MQI 通道。这会创建四个消息管道(两个事务性和两个非事务性)在两个队列系统间路由消息。创建完成之后,需要公开客户端和服务器的定义。将这些文件复制到 WebSphere MQ 计算机,然后使用 runmqsc 命令将它们导入。这个命令配置传输队列并跨越桥接保持信道的同步。 下一步是在 WebSphere MQ 中创建本地和远程队列。通过桥接配置远程队列以指向 MSMQ 队列。通过配置远程队列管理器名和传输队列名以指向导入创建的对象来完成此操作。 最后,需要从运行 WebSphere MQ 的计算机将 WebSphere MQ 客户端通道表文件复制到 MSMQ 计算机,并配置 MQCHLLIB 和 MQCHLTAB 环境变量以指向该文件。 选择数据格式 使用 MSMQ-MQSeries 桥发送队列上的消息时,必须确保接收端可以使用该消息数据。在 J2EE 和 .NET Framework 间发送复杂数据的唯一现实的方法是将数据序列化成 XML 格式的字符串。此外,WebSphere MQ 支持发送 TextMessages,可以加载带有包含要发送的 XML 数据的字符串的正文。MSMQ 还允许发送包含 XML 格式字符串的简单消息。 注 使用其它的数据类型不可行,因为如同第 3 章“互用性基本原理”中所述,在 .NET Framework 和 J2EE 间存在二进制序列化差异。 创建消息使用者 本指南已说明了为什么消息使用者是一个应用程序,可创建以用于轮询并读取队列中的消息,并将它们放在资源外观中。因为使用的是桥接,所以使用 XML 格式的字符串。因此,在能够使用数据调用资源外观上的方法之前,必须从 XML 字符串中重建数据。随后两节介绍了如何在两个平台上完成此操作。 创建 .NET Framework 消息使用者 如同第 5 章“互用性技术:数据层”所述,.NET Framework 消息使用者从 MSMQ 队列读取消息。读取消息内容之后,必须重建数据。有关完成此操作的技术的信息,请参阅第 7 章“在表示层集成 .NET”中的“Web 服务”一节。 下列代码示例显示了如何从 MSMQ 读取消息,以及用于构建正确 .NET Framework 数据类型的数据。 MessageQueue q = new MessageQueue(_queueName); q.Formatter = new XmlMessageFormatter( new Type[] {typeof(String)} ); Message order = q.Receive(0); string xml = (string) order.Body(); StringReader sr = new StringReader(xml); OrderData ds = new OrderData(); // Load result string back into an OrderData-typed DataSet ds.ReadXml(sr); 注 前面的示例使用来自 XBikes 的 OrderData 自定义数据类型。然而,XBikes 应用程序不实现该代码。 创建 J2EE 消息使用者 J2EE 消息使用者从 WebSphere MQ 读取消息,可以使用 MQI Java 类或 JMS 来构建 WebSphere MQ。在读取消息后,必须从 XML 字符串重建 Java 数据。有关如何完成此操作的技术的信息,请参阅第 8 章“在业务层集成 .NET”的“Web 服务”一节。 下列代码示例显示了从 WebSphere MQ 读取消息,以及用来构建正确 J2EE 数据类型的数据。 String connectionName = "XBikesQFC"; InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ic.lookup(queueName); QueueReceiver receiver = session.createReceiver(queue); connection.start(); TextMessage message = (TextMessage) receiver.receive(); String orderXML = message.getText(); OrderData order = OrderConverter.stringtoOrderData(orderXML); DalServiceFacade facade = getFacadeHome().create(); return facade.saveOrder(order); 注 前面示例使用了 OrderData 自定义数据类型和来自 XBikes 的 OrderConverter 类。然而,XBikes 应用程序不实现该代码。 创建互用性适配器 根据本指南中已论述的技术,建议创建异步互用性适配器来提供到异步通讯通道的访问。本适配器将消息数据序列化为 XML 格式的字符串。 创建 .NET Framework 异步互用性适配器 .NET Framework 应用程序将消息发送给 MSMQ,因此可以使用 .NET Framework 类来完成此操作,如第 5 章所述。因为消息的最终目的地是 WebSphere MQ,所以必须将消息编写为字符串。 如果使用数据集,则可以用 方法来提取 XML。然后可将 XML 字符串像放入 MSMQ 消息队列中,如以下代码示例所示。 string xml = order.GetXml(); MessageQueue q = new MessageQueue(_queueName); q.Send(xml); 注 先前示例使用的 OrderData 类源自 XBikes 应用程序中出现的 order 对象。然而 XBikes 应用程序不实现该代码。 创建 J2EE 异步互用性适配器 J2EE 应用程序将消息发送给 WebSphere MQ,因此可使用 JMS 类(或者 MQI)来发送此消息。此外,因为最终的消息目的地是 MSMQ,所以必须创建字符串消息而不是编写对象。 有关将 Java 数据序列化为 XML 字符串的背景知识和代码,请参阅第 7 章的“Web 服务”一节。为了发送消息,可以使用与以下示例类似的 JMS 代码。 InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup("XBikesQCF"); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ic.lookup("XBikesQ"); QueueSender sender = session.createSender(queue); sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); sender.setPriority(4); sender.setTimeToLive(0); connection.start(); // Use a text message TextMessage message = session.createTextMessage(); // Convert the order to a string String sorder = OrderConverter.orderListDataToString(orderObject); message.setText(sorder); sender.send(message); 注 前面的示例使用了源自 XBike 的OrderData 和 OrderConverter 类。然而,XBikes 应用程序不实现该代码。 现在已说明如何实现 MSMQ-MQSeries 桥,接下来说明异步互用性的运行库桥接。 使用 JNBridgePro 第 4 章“互用性技术:点对点”说明了 JNBridgePro 如何创建 Java 类的 .NET Framework 代理。这些 .NET Framework 代理允许 .NET Framework 应用程序与本地 Java 类交互。倘若异步互用性的技术之一是为 Java 上的 JMS 类创建代理类,则该技术提供从 .NET Framework 调用 JMS 消息的功能。本解决方案与目前所论述过的解决方案有所不同,因为 .NET Framework 不能直接与消息队列交互,所以它将通过 Java 进行通讯。因此,需要运行 J2EE 应用程序的服务器来提供带有 JMS 访问的 .NET Framework。 图 9.4 显示了异步通讯中 JNBridge 的角色。  图" 9.4:异步通讯中 JNBridge 的角色 注 因为 JNBridgePro 包装 JMS,所以除了配置 WebSphere MQ 的 JMS 支持外,不需要特殊配置。 确定 JNBridgePro 的数据格式 JNBridgePro 包装 JMS 功能,允许将 Java 对象直接放入消息队列中。从数据的观点出发,唯一的任务是创建 Java 数据对象的 .NET Framework 代理 ,用来自 .NET Framework 的数据进行填充,然后用这个对象编写消息。 为 JNBridgePro 创建消息使用者 因为 JNBridgePro 适配器将 JMS 消息放入 WebSphere MQ 中,所以可使用标准的 JMS 代码来读取消息。带有 JNBridgePro 包装的 JMS 决定读取消息的格式,因此无需更改可直接发送至资源应用程序的数据。以下代码示例显示了如何从 JMS 读取消息。 InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ic.lookup(queueName); QueueReceiver receiver = session.createReceiver(queue); connection.start(); ObjectMessage message = (ObjectMessage) receiver.receive(); order = (OrderData) message.getObject(); DalServiceFacade facade = getFacadeHome().create(); return facade.saveOrder(order); 为 JNBridgePro 创建异步互用性适配器 要创建异步互用性适配器,需要将 JMS 类从 J2EE 公开到 .NET Framework 应用程序。可以使用 JNBridgePro 代理生成工具,以第 7 章所述实现互用性的相同方式来完成此项操作。 若要创建代理,需添加 j2ee.jar、jndi.jar 和 jms.jar 软件包以及 JNBridgePro classpath 所需的所有应用程序指定的数据类。必须为下列类创建代理: • javax.naming.InitialContext • javax.naming.NamingException • javax.jms.QueueConnectionFactory • javax.jms.QueueConnection • javax.jms.QueueSession • javax.jms.Session • javax.jms.Queue • javax.jms.QueueSender • javax.jms.ObjectMessage • javax.jms.JMSException • javax.jms.DeliveryMode • javax.jms.InvalidDestinationException 在 XBikes 示例应用程序中,该列表还包括 xbikes.common.data 软件包中的类。 生成代理和配置 .NET Framework 应用程序后,.NET Framework 互用性适配器以与 J2EE 应用程序所使用的类似的方法调用代理类。以下代码示例显示了如何在 .NET Framework 的 WebSphere 中创建新的 JMS 消息。 InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName); QueueConnection connection = factory.createQueueConnection(); connection.start(); QueueSession session = connection.createQueueSession(false, SessionConstants.AUTO_ACKNOWLEDGE); javax.jms.Queue queue = (javax.jms.Queue) ic.lookup(queueName); QueueSender sender = session.createSender(queue); ObjectMessage message = session.createObjectMessage(order); sender.send(message); 注 这几乎等同于从 Java 发送 JMS 消息,但是语言是 C#。 下一节内容为同样的技术,但使用的是 Ja.NET 而不是 JNBridgePro。 使用 Ja.NET 第 4 章内容说明了 Ja.NET 如何为 Java 类定义 .NET Framework 代理类,以使 .NET Framework 应用程序能够访问 Java 类。以类似的方法,可以定义 Java JMS 类的 .NET Framework 代理类,以使 .NET Framework 应用程序能够调用 JMS 消息。本解决方案不同于目前所论述过的其他解决方案,因为 .NET Framework 应用程序通过 Java 进行通讯,而不是直接与消息队列交互。这个实现要求运行 J2EE 应用程序服务器来提供带有 JMS 访问的 .NET Framework。 乍一看,它与 JNBridgePro 解决方案相同,然而,Ja.NET 附带有已经建立的 JMS 代理。这是因为所有的 JMS 调用均通过接口实现。因此在使用 Ja.NET 时无需自己创建代理。 图 9.5 显示了异步通讯中 Ja.NET 的角色。  图" 9.5:异步通讯中 Ja.NET 的角色 此外,需要配置消息队列并确定数据格式。 配置消息队列 因为 Ja.NET 为 JMS 提供包装,所以此处不要求特殊配置。然而,还是需要为 JMS 支持配置 WebSphere MQ。 确定 Ja.NET 的数据格式 因为 Ja.NET 包装 JMS 功能,所以可直接将 Java 对象放入消息队列中。从数据的角度看,唯一的任务是创建 Java 数据对象的 .NET Framework 代理,用来自 .NET Framework 的数据进行填充,随后用该对象编写消息。 为 Ja.NET 创建消息使用者 因为 Ja.NET 适配器将 JMS 消息放入 WebSphere MQ 中,所以可以使用标准的 JMS 代码来读取消息。消息用 Ja.NET 包装成 JMS 格式,因此无需更改数据。这样可直接将其发送到资源应用程序。以下代码示例显示了如何从 JMS 读取消息。 InitialContext ic = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ic.lookup(connectionName); QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ic.lookup(queueName); QueueReceiver receiver = session.createReceiver(queue); connection.start(); ObjectMessage message = (ObjectMessage) receiver.receive(); order = (OrderData) message.getObject(); DalServiceFacade facade = getFacadeHome().create(); return facade.saveOrder(order); 下一节内容是创建异步互用性适配器。 创建Ja.NET 异步互用性适配器 为了创建该适配器,需使用 Ja.NET 1.5 附带的、预先包装的 JMS 代理。该代理是强名称,因此可以从 COM+ 上下文中使用它而不会产生问题。还必须为要从 .NET Framework 访问的任何 Java 数据类型创建代理类。记住在将消息放入队列前,将数据打包成 Java 类。 注 第 7 章包含为 Ja.NET 生成代理的详细信息。 以下代码示例显示了如何使用 Ja.NET 将消息从 .NET Framework 发送到 JMS 队列。 JNDIContext context = new JNDIContext(); object o = context.Lookup("javax.jms.QueueConnectionFactory", "XBikesQCF"); javax.jms.QueueConnectionFactory factory = (javax.jms.QueueConnectionFactory) o; QueueConnection connection = factory.createQueueConnection(); QueueSession session = connection.createQueueSession(false, SessionConstants.AUTO_ACKNOWLEDGE); javax.jms.Queue queue = (javax.jms.Queue) context.Lookup("javax.jms.Queue", "XBikesQ"); QueueSender qSender = session.createSender(queue); qSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT); qSender.setPriority(4); qSender.setTimeToLive(0); connection.start(); ObjectMessage message = (ObjectMessage)session.createObjectMessage(); message.setObject(ejbOrder); qSender.send(message); 此外,这几乎与从 Java 发送 JMS 消息相同,但语言是 C#。 小结 本章描述了通过使用到消息队列组件的异步连接,从 .NET Framework 业务层连接到 Java 环境的机制。其中还包括配置运行库桥接以进行连接,并同时使用 JNBridgePro 和 Ja.NET 的代理。
|
|