我们最近发现大量的客户都有一个同样的问题:在运行于JBoss Wildfly 7中的HornetQ JMS实现和独立运行的ActiveMQ服务器之间,如何才能建立一个桥接。ActiveMQ作为一个独立运行的消息代理(message broker),一直是一个可靠的选择。而且随着Red Hat已经收购了Fusesource(译者注:Fusesource是ActiveMQ项目的维护组织,Red Hat此前在2006年收购了JBoss,现在JBoss和Fusesource都是Red Hat旗下的开源组织),在等待JBoss AMQ版本的ActiveMQ推出期间(译者注:JBoss基于ActiveMQ定制了一个新MQ,官方名称为JBoss A-MQ),这个问题尤其突出。 不使用桥接当然也是可能的,直接可以把ActiveMQ引入到JBoss,然后使用ActiveMQ上暴露的JMS队列。但是这个方式的缺点在于,如果ActiveMQ服务器由于某些原因停止工作的话,运行于JBoss中的JMS生产者将会失败,消费者也将会断开连接并且需要重连(译者注:原文拼写错误,误将reconnect拼写为reconnet)。一个更好的架构是,JBoss中的生产者先入列到一个本地HornetQ队列,然后将这些消息桥接到外部的ActiveMQ代理。在这个架构中,生产者可以在ActiveMQ宕机期间持续地入列消息,等到ActiveMQ再次工作时这些消息将会从HornetQ传输到ActiveMQ。 配置桥接的过程是相当简单的,我们需要做以下的事情:
这将会创建一个包含模块层次结构的目录,并将activemq资源适配器文件解压到此目录.JBoss只支持把拓展的资源适配器作为模块,所以我们解压归档文件的内容.同时,我们需要在activemq/main目录,创建一个包含如下内容的module.xml文件.这是为了让JBoss区分,哪些jar文件需要加装,哪些类不需要和其它模块共享(我们不希望和任何库的实现相冲突).
要对模块进行配置我们需要编辑JBoss的配置文件,这里我从standalone-full.xml开始,因为它已经对HornetQ进行了配置(这节省了我们很多时间)。我们需要添加activeMQ资源适配器,把下面这一行
改成
这样就创建了一个资源适配器,它使用了我们刚才创建的org.apache.activemq 模块,并连接到了运行在 tcp://localhost:61616上的远程ActiveMQ服务器上。它注册了一个连接工厂,名叫java:AMQConnectionFactory 使得我们可以连到远程服务器上,也创建了一个名为queue/JMSBridgeTargetQ的本地JNDI,该JNDI将被绑定到名为JMSBridgeTargetQ的ActiveMQ队列上。 下一步就是配置桥接器和本地队列。我们来编辑hornetq子系统,在hornetQ 服务器的定义后面,添加一个JMS桥接器。
这样就创建了一个桥接器,它使用名为ConnectionFactory 的连接工厂来消耗本地队列里的消息,该队列对应的JNDI名字是queue/JMSBridgeSourceQ。随后它将使用一个名为AMQConnectionFactory 的连接工厂(它由我们的资源适配器创建)来把消息发送到JNDI名称为queue/JMSBridgeTargetQ的本地队列中。我们的资源适配器会把这映射到远程ActiveMQ队列中。我们也需要在该配置文件的jms-destinations部分里,创建一个名为JMSBridgeSourceQ 的本地队列。
这个队列有两个JNDI名称,使得它可以同时从内部(被桥接器)和外部(被客户端)访问到. 为了在ActiveMQ创建一个通信目的地, 我们通过bin/activemq开始命令启动ActiveMQ,并使用ActiveMQ hawtio控制台(http://localhost:8161/hawtio),通过浏览ActiveMQ -> Broker -> Localhost -> Queue并选择Create来创建一个新的JMS队列.在这个例子中设置队列名为JMSBridgeTargetQ. 这就是所有必需的配置文件.我们应该可以启动WildFly服务,看到桥接开始工作并连接到ActiveMQ.
我们现在可以在JBoss的JMSBridgeSourceQ里面放置消息,它们最后将处于ActiveMQ的JMSBridgeTargetQ之中. 将桥接的消息流方向反过来也是可能的,尽管消费者的桥接和生产者的桥接并非同样至关重要.消费者的桥接,通常更倾向于直接从映射的JNDI名字(在queue/JMSBridgeTargetQ里面,由资源适配器创建)获取消息,而不是将消息放置在本地队列后,再从本地获取消息. |