我正在寻找替代插件方法(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或路由插件?
答案 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
}
}