Grails和ActiveMQ:如何管理DefaultMessageListenerContainer的连接

时间:2013-05-10 06:44:39

标签: grails jms activemq

我正在寻找替代插件方法(jms和/或camel路由插件)来消费Grails的ActiveMQ。到目前为止一切顺利,但我无法找到任何管理连接的好解决方案。

这是我的config / spring / resources.groovy:

import org.springframework.jms.connection.SingleConnectionFactory
import org.apache.activemq.ActiveMQConnectionFactory
import org.springframework.jms.listener.adapter.MessageListenerAdapter
import org.springframework.jms.listener.DefaultMessageListenerContainer

beans = {
    jmsConnectionFactory(SingleConnectionFactory) {
        targetConnectionFactory = { ActiveMQConnectionFactory cf ->
            brokerURL = "tcp://localhost:61616"
        }
    }

    jmsMessageListener(MessageListenerAdapter, ref("myService")) {
        defaultListenerMethod = "onIncomingMessage"
    }

    jmsContainer(DefaultMessageListenerContainer) {
        connectionFactory = jmsConnectionFactory
        destinationName = "StatusSavedTopic"
        messageListener = jmsMessageListener
        autoStartup = true

        // Tells the magic sauce to be an ActiveMQ topic
        pubSubDomain = true
    }
}

如果我将autoStartup设置为true,则它与run-app一起正常工作,直到我保存我的服务,导致重新编译。发生这种情况时,连接将被删除(通过检查ActiveMQ Web控制台确认),并且不会再收到任何消息(显然)。

有没有办法确保我的jmsContainer保持活着,除非不是手动操作并使用jms或路由插件?

1 个答案:

答案 0 :(得分:2)

我正在回答自己,因为我找到了解决方案。

解决方案是在进程中嵌入ActiveMQ代理。我总是将消息发布到这个嵌入式代理,我不必测试它的可用性或处理重新连接,原因很明显 - 它就在我的过程中。

然后,ActiveMQ本身就有了一种连接代理的方法,以便一个中的消息总是传递到下一个,并且ActiveMQ会自动处理所有连接内容。如果代理启动时代理停止,则初始连接;如果代理在运行中停止,则重新连接。

您也可以自由选择嵌入式代理的存储空间。如果您将邮件保留到磁盘,如果您的应用程序在嵌入式代理中排队邮件但在ActiveMQ设法传递到中央代理之前停止,则ActiveMq还会负责将邮件发送到中央代理。

这是grails-app / conf / spring中的bean代码,用于设置应用程序。我有点像春天的菜鸟,所以我相信有更好的方法。使用MethodInvokingFactoryBean可以很容易地不用Spring本身进行所有花哨的初始化,这有助于我在旅途中获得这个节目。

activemqLocalMessageDeliveryConnection(org.springframework.beans.factory.config.MethodInvokingFactoryBean) {
    targetClass = "com.myapp.ActiveMQLocalBrokerHelper"
    targetMethod = "createConnection"
    arguments = [ref("grailsApplication")]
}

activemqLocalMessageDeliveryProducerSession(org.springframework.beans.factory.config.MethodInvokingFactoryBean) {
    targetClass = "com.myapp.ActiveMQLocalBrokerHelper"
    targetMethod = "createProducerSession"
    arguments = [ref("activemqLocalMessageDeliveryConnection")]
}

activemqLocalMessageDeliveryProducer(org.springframework.beans.factory.config.MethodInvokingFactoryBean) { bean ->
    targetClass = "com.myapp.ActiveMQLocalBrokerHelper"
    targetMethod = "createProducer"
    arguments = [ref("grailsApplication"), ref("activemqLocalMessageDeliveryProducerSession")]
}

以下是ActiveMQLocalBrokerHelper的代码。

package com.myapp
import java.io.File
import org.apache.activemq.command.ActiveMQDestination

class ActiveMQLocalBrokerHelper {
    static javax.jms.Connection createConnection(grailsApplication) {
        // http://activemq.apache.org/how-do-i-embed-a-broker-inside-a-connection.html
        def localBrokerName = "localMessageDelivery"

        def broker = new org.apache.activemq.broker.BrokerService()
        broker.setPersistent(false)
        broker.setBrokerName(localBrokerName)
        broker.start()

        def connFactory = new org.apache.activemq.ActiveMQConnectionFactory(broker.getVmConnectorURI());
        def conn = connFactory.createConnection();
        conn.start()

        return conn
    }

    static javax.jms.Session createProducerSession(conn) {
        def session = conn.createSession(true, javax.jms.Session.AUTO_ACKNOWLEDGE);
        return session
    }

    static javax.jms.MessageProducer createProducer(grailsApplication, session) {
        def destination  = session.createQueue("MessageDelivery")
        def producer = session.createProducer(destination)
        producer.setDeliveryMode(javax.jms.DeliveryMode.NON_PERSISTENT)
        return producer
    }
}

这就是获得嵌入式ActiveMQ代理所需的全部内容。这个特定的不持久,并且是事务性的。当然,你可以自由地使用ActiveMQ Java API来做任何事情。要排队和使用消息,只需使用常规的ActiveMQ API即可。例如:

def activemqLocalMessageDeliveryProducer // Inject the producer
def activemqLocalMessageDeliveryProducerSession // And the session

void enqueue(String messageText) {
    def message = session.createTextMessage(messageText)
    producer.send(message)
    session.commit()
}

用于消费:

def activemqLocalMessageDeliveryConnection // Inject the connection

void consume() {
    def activemqSession = activemqLocalMessageDeliveryConnection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
    def destination = activemqSession.createQueue("MyQueueName")
    def consumer = activemqSession.createConsumer(destination)
    while (true) {
        def message = consumer.receive()
        // Do something with message
    }
}