寻找解决方案
由于此场景很显然属于异步方式,因此非常适合通过消息传递模式实现。事实上,使用面向消息的中间件通常可以利用高级功能来保证消息的可靠交付,即便使用者(诊所)暂时断开连接也可以保证这一点。这些功能在使用基于 Web 服务的单向交互时通常不可用。就这些考虑而言,ESB 非常适合此场景,因为它不仅能够保证基于消息的连接性,还提供了透明传输协议切换功能。这些功能利用了可以在 ESB 内为服务定义的绑定概念。通过这些绑定,用户可以提供协议特定的设置来告知 ESB 如何管理传入和传出消息。导出绑定描述客户机如何与中介模块通信。导入绑定则描述中介模块如何与所定义的服务通信。这些绑定使得不用在应用程序代码中放入任何通信逻辑的情况下连接到诊所成为可能。要实现所描述的场景,我们定义了中介模块,并将其连接到 SOAP/HTTP 导出绑定和 JMS 导入绑定,如图 2 中所示。
图 2. 中介模块

通过这样,中介模块可以接收采用 SOAP/HTTP 协议的消息,并能够根据 JMS 协议对这些消息进行转换。导入绑定允许用户指定必须将这些消息送到的目的地。此目的地可以为主题或队列,具体取决于应用程序的域。使用队列具有在服务请求者和服务提供者之间提供专用通信通道的优势,但同时也有缺点,即要求在 ESB 上为每个已部署的服务提供者配置一个队列。使用主题可以避免域队列相关的配置负担,但同时又要求注册到主题的所有诊所侦听送达的消息。这样做的话,诊所可能还会收到以其他提供者为目的地的消息,而在考虑保密性和带宽使用的情况下,这就成了需要考虑的问题。在本文稍后,我们将给出这些限制的实用解决方案。这里我们从体系结构的角度对此解决方案进行了描述,但您可以在本系列的第三篇文章中找到关于技术实现和配置相关方面的所有细节。
使用消息选择器避免带宽消耗
根据 JMS 规范,可以定义一些作为筛选器的消息,以告知 JMS 客户机应该处理哪些消息(仅处理以其为目的地的消息)。此信息在消息转发到 JMS 主题前可以放在某个非保留 JMS Header 中(例如,JMSType 中)或基于 JMS 的其他属性中。在此场景中,每个服务提供者通过 serviceProviderId 代码明确地标识。中央预约系统有一个包含这些标识代码的列表,每个提供者在其中都有一个标识代码。当预约系统向服务提供者发送更新日程表时,预约系统将准备一条 SOAP 消息(稍后将给出其格式),并将正确的标识代码添加到消息的主体,然后将其转发给 ESB。如果 ESB 负责将此消息转换为 JMS 有效负载并转发到预定义的主题,看起来似乎应该在 ESB 内实现逻辑来使用这些标识代码扩充 JMS 消息 Header,从而使用消息主体中包含的 serviceProviderId 作为消息选择器。幸运的是,ESB 提供了 message element setter 中介原语,可以将其用于检查传入消息格式并向传出消息 Header 添加一些信息。此原语已在 WebSphere Enterprise Service Bus V6.0.2 中引入,并在此解决方案中用于扩充 JMS 消息 Header,如图 3 中所示。
图 3. 消息选择器

中介模块收到请求消息时,会使用 message setter 原语从请求的 SOAP 主体检索 serviceProviderId,以便将其存储(通过复制操作)在传出消息的 JMSHeader 中。然后 ESB 将此消息转发到主题,从而使得诊所可靠地得到此消息。此解决方案不需要在 ESB 层提供代码。不过,显然有必要在客户端开发 JMS 独立应用程序或消息驱动的 Bean 来触发诊所与主题的交互。
保证主题上的数据保密性
正如前面所述的,使用主题可以避免队列相关的配置负担,但同时又有一个缺点,即要求注册到主题的所有诊所侦听送达主题的消息。即使在 ESB 上配置消息选择器可以让服务提供者仅仅获得自己的消息,但此解决方案并不会防止恶意客户机在没有消息选择器的情况下注册主题,从而侦听所有传入消息。为了克服这个限制,同时也为了让这个场景更有意义,我们决定采用 PKI。
图 4. 公钥基础设施
我们假定每个诊所都具有自己的证书,并将其发布到了中央预约系统。您可以在图 5 中看到其具体情况。正如前面所说的,进入预约系统的每个 SOAP 请求都在消息的主体中包含标识消息必须送达的提供者的信息 (serviceProviderId)。从特定服务提供者获取 SOAP 消息时,中央预约系统会解析消息,获取 serviceProviderId 并使用此信息动态地选择服务提供者所发布的证书,然后使用其加密消息。当然,在客户端,只有 serviceProviderId 标志标识的服务提供者能够理解此消息,因为其具有执行解密所需的正确私钥。不过,恶意注册主题的服务提供者将无法理解消息,因为无法使用匹配的私钥对其进行解密。通过这样,可以确保主题上的数据保密性,不过必须在中央预约系统上实现某种逻辑来加密消息。为了避免在加密消息时必须执行 SOAP/XML 封送和取消封送的负担,我们决定使用 SOA 设备,委托 WebSphere DataPower SOA Appliances 单元来负责对 SOA 消息主体的保密部分执行基于 XML 标准的加密操作。
图 5. 证书管理
中央预约系统的管理员负责从诊所获得证书,然后将证书上传到 WebSphere DataPower SOA Appliances。WebSphere DataPower SOA Appliances 充当 Web 服务代理;它将传入 SOAP 请求进行加密,并将经过加密的消息发送到 ESB(有关进一步的信息,请参见本系列的下一篇文章)。