JBoss WildFly 7 连接到 ActiveMQ 5.9
我们最近发现大量的客户都有一个同样的问题:在运行于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。
配置桥接的过程是相当简单的,我们需要做以下的事情:
1. 下载ActiveMQ资源适配器归档文件 2. 在WildFly 7中安装和配置资源适配器 3. 在WildFly 7内嵌的HornetQ实例中,创建一个本地JMS队列 4. 在本地队列和远程ActiveMQ队列之间,创建一个JMS桥接.
为了开始, 我下载了ActiveMQ资源适配器,从这个页面:http://repo1.maven.org/maven2/org/apache/activemq/activemq-rar/ 下一步,我们需要使用如下的命令,为activemq资源适配器,创建一个JBoss模块,:
mkdir modules/system/layers/base/org/activemq/main cd modules/system/layers/base/org/activemq/main unzip ~/activemq-rar-5.9.0.rar
这将会创建一个包含模块层次结构的目录,并将activemq资源适配器文件解压到此目录.JBoss只支持把拓展的资源适配器作为模块,所以我们解压归档文件的内容.同时,我们需要在activemq/main目录,创建一个包含如下内容的module.xml文件.这是为了让JBoss区分,哪些jar文件需要加装,哪些类不需要和其它模块共享(我们不希望和任何库的实现相冲突).
<module xmlns="urn:jboss:module:1.1" name="org.apache.activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <resources> <resource-root path="."/> <resource-root path="activemq-broker-5.9.0.jar"/> <resource-root path="activemq-client-5.9.0.jar"/> <resource-root path="activemq-jms-pool-5.9.0.jar"/> <resource-root path="activemq-kahadb-store-5.9.0.jar"/> <resource-root path="activemq-openwire-legacy-5.9.0.jar"/> <resource-root path="activemq-pool-5.9.0.jar"/> <resource-root path="activemq-protobuf-1.1.jar"/> <resource-root path="activemq-ra-5.9.0.jar"/> <resource-root path="activemq-spring-5.9.0.jar"/> <resource-root path="aopalliance-1.0.jar"/> <resource-root path="commons-pool-1.6.jar"/> <resource-root path="commons-logging-1.1.3.jar"/> <resource-root path="hawtbuf-1.9.jar"/> <resource-root path="spring-aop-3.2.4.RELEASE.jar"/> <resource-root path="spring-beans-3.2.4.RELEASE.jar"/> <resource-root path="spring-context-3.2.4.RELEASE.jar"/> <resource-root path="spring-core-3.2.4.RELEASE.jar"/> <resource-root path="spring-expression-3.2.4.RELEASE.jar"/> <resource-root path="xbean-spring-3.14.jar"/> </resources> <exports> <exclude path="org/springframework/**"/> <exclude path="org/apache/xbean/**"/> <exclude path="org/apache/commons/**"/> <exclude path="org/aopalliance/**"/> <exclude path="org/fusesource/**"/> </exports> <dependencies> <module name="Javax.api"/> <module name="org.slf4j"/> <module name="javax.resource.api"/> <module name="javax.jms.api"/> <module name="javax.management.j2ee.api"/> </dependencies> </module>
要对模块进行配置我们需要编辑JBoss的配置文件,这里我从standalone-full.xml开始,因为它已经对HornetQ进行了配置(这节省了我们很多时间)。我们需要添加activeMQ资源适配器,把下面这一行
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.0"/>
改成
<subsystem xmlns="urn:jboss:domain:resource-adapters:1.1"> <resource-adapters> <resource-adapter id="activemq-rar.rar"> <module slot="main" id=" org.apache.activemq "/> <transaction-support>NoTransaction</transaction-support> <config-property name="ServerUrl"> tcp://localhost:61616 </config-property> <connection-definitions> <connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name=" java:/AMQConnectionFactory " enabled="true" use-java-context="true" pool-name="AMQConnectionFactory"/> </connection-definitions> <admin-objects> <admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name=" queue/JMSBridgeTargetQ " use-java-context="true" pool-name="target_queue"> <config-property name="PhysicalName"> JMSBridgeTargetQ </config-property> </admin-object> </admin-objects> </resource-adapter> </resource-adapters> </subsystem>
这样就创建了一个资源适配器,它使用了我们刚才创建的 org.apache.activemq 模块,并连接到了运行在 tcp://localhost:61616 上的远程ActiveMQ服务器上。它注册了一个连接工厂,名叫 java:AMQConnectionFactory 使得我们可以连到远程服务器上,也创建了一个名为 queue/JMSBridgeTargetQ 的本地JNDI,该JNDI将被绑定到名为 JMSBridgeTargetQ 的ActiveMQ队列上。
下一步就是配置桥接器和本地队列。我们来编辑hornetq子系统,在hornetQ 服务器的定义后面,添加一个JMS桥接器。
<jms-bridge name="simple-jms-bridge"> <source> <connection-factory name=" ConnectionFactory "/> <destination name=" queue/JMSBridgeSourceQ "/> </source> <target> <connection-factory name=" AMQConnectionFactory "/> <destination name=" queue/JMSBridgeTargetQ "/> </target> <quality-of-service>AT_MOST_ONCE</quality-of-service> <failure-retry-interval>1000</failure-retry-interval> <max-retries>-1</max-retries> <max-batch-size>10</max-batch-size> <max-batch-time>100</max-batch-time> </jms-bridge> .
这样就创建了一个桥接器,它使用名为 ConnectionFactory 的连接工厂来消耗本地队列里的消息,该队列对应的JNDI名字是 queue/JMSBridgeSourceQ 。随后它将使用一个名为 AMQConnectionFactory 的连接工厂(它由我们的资源适配器创建)来把消息发送到JNDI名称为 queue/JMSBridgeTargetQ 的本地队列中。我们的资源适配器会把这映射到远程ActiveMQ队列中。我们也需要在该配置文件的jms-destinations部分里,创建一个名为 JMSBridgeSourceQ 的本地队列。
<jms-destinations> <jms-queue name="JMSBridgeSourceQueue"> <entry name=" java:/queue/JMSBridgeSourceQ "/> <entry name="java:jboss/exported/jms/queue/JMSBridgeSourceQ "/> <durable>true</durable> </jms-queue> </jms-destinations>
这个队列有两个JNDI名称,使得它可以同时从内部(被桥接器)和外部(被客户端)访问到.
为了在ActiveMQ创建一个通信目的地, 我们通过 bin/activemq 开始命令启动ActiveMQ,并使用ActiveMQ hawtio控制台(http://localhost:8161/hawtio),通过浏览ActiveMQ -> Broker -> Localhost -> Queue并选择Create来创建一个新的JMS队列.在这个例子中设置队列名为 JMSBridgeTargetQ .
这就是所有必需的配置文件.我们应该可以启动WildFly服务,看到桥接开始工作并连接到ActiveMQ.
13:43:11,959 INFO [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on 127.0.0.1:9999 13:43:12,447 INFO [org.jboss.as.remoting] (MSC service thread 1-2) JBAS017100: Listening on 127.0.0.1:4447 13:43:12,452 INFO [org.jboss.as.connector.deployers.RaXmlDeployer] (MSC service thread 1-2) IJ020001: Required license terms for file:/home/matt/jboss-as-7.2.0.Final/modules/system/layers/base/org/apache/activemq/main/./ 13:43:12,511 INFO [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010406: Registered connection factory java:/AMQConnectionFactory 13:43:12,522 INFO [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010405: Registered admin object at java:/queue/JMSBridgeTargetQ 13:43:12,538 INFO [org.hornetq.core.server] (MSC service thread 1-1) HQ221024: Started Netty Acceptor version 3.6.2.Final-c0d783c 127.0.0.1:5455 for CORE protocol 13:43:12,550 INFO [org.jboss.as.connector.deployers.RaXmlDeployer] (MSC service thread 1-2) IJ020002: Deployed: file:/home/matt/jboss-as-7.2.0.Final/modules/system/layers/base/org/apache/activemq/main/./ 13:43:12,555 INFO [org.hornetq.core.server] (MSC service thread 1-1) HQ221024: Started Netty Acceptor version 3.6.2.Final-c0d783c 127.0.0.1:5445 for CORE protocol 13:43:12,558 INFO [org.hornetq.core.server] (MSC service thread 1-1) HQ221009: Server is now live 13:43:12,561 INFO [org.hornetq.core.server] (MSC service thread 1-1) HQ221003: HornetQ Server version 2.3.0.CR1 (buzzzzz!, 122) [1ef84f49-88d8-11e3-a2ac-f9239574df9d] 13:43:12,584 INFO [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-1) JBAS010400: Bound data source [java:jboss/datasources/ExampleDS] 13:43:12,600 INFO [org.jboss.as.connector.deployment] (MSC service thread 1-1) JBAS010401: Bound JCA ConnectionFactory [java:/AMQConnectionFactory] 13:43:12,611 INFO [org.jboss.as.connector.deployment] (MSC service thread 1-1) JBAS010401: Bound JCA AdminObject [java:/queue/JMSBridgeTargetQ] 13:43:12,683 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 58) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/RemoteConnectionFactory 13:43:12,686 INFO [org.hornetq.core.server] (ServerService Thread Pool -- 60) HQ221005: trying to deploy queue jms.queue.JMSBridgeSourceQueue 13:43:12,733 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 60) JBAS011601: Bound messaging object to jndi name java:jboss/exported/jms/queue/JMSBridgeSourceQ 13:43:12,738 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 60) JBAS011601: Bound messaging object to jndi name java:/queue/JMSBridgeSourceQ 13:43:12,747 INFO [org.jboss.as.messaging] (ServerService Thread Pool -- 59) JBAS011601: Bound messaging object to jndi name java:/ConnectionFactory 13:43:12,916 INFO [org.jboss.as.connector.deployment] (MSC service thread 1-2) JBAS010406: Registered connection factory java:/JmsXA 13:43:12,968 INFO [org.hornetq.ra] (MSC service thread 1-2) HornetQ resource adaptor started