我正在尝试实现以下方案并使用JMS API。使用DefaultMessageListenerContainer接收消息
场景 - 我有一个发布者,它将消息发布到RabbitMQ交换机和监听RMQ队列以接收消息的侦听器。 如果在侦听器上处理收到的消息时发生异常,则该消息或消息组应回滚并放回同一队列中。
我使用属性“session transacted = true”通过本地事务实现上述场景。但是,当出现异常时,我的消息没有回滚到原始队列。如果我在这里遗漏任何东西,有人可以提供帮助。
Spring bean配置如下。
<bean id="rmqConnectionFactory" class="com.rabbitmq.jms.admin.RMQConnectionFactory">
<property name="username" value="guest"/>
<property name="password" value="guest"/>
<property name="host" value="localhost"/>
<property name="port" value="5672"/>
<property name="virtualHost" value="/"/>
</bean>
<bean id="rmqDestination" class="com.rabbitmq.jms.admin.RMQDestination">
<property name="destinationName" value="testDestination"/>
<property name="amqpExchangeName" value="testExchange"/>
<property name="amqpRoutingKey" value="testRouting"/>
<property name="amqpQueueName" value="testDestination"/>
</bean>
<bean id="messageListener" class="org.jms.SimpleJMSMessageListener" />
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="rmqConnectionFactory"/>
<property name="destination" ref="rmqDestination"/>
<property name="messageListener" ref="messageListener" />
<property name="sessionTransacted" value="true"/>
</bean>
Message Listener如下:
public class SimpleJMSMessageListener implements MessageListener {
@Transactional
@Override
public void onMessage(Message message) {
int num[] = {1, 2, 3, 4};
if (message instanceof TextMessage) {
try {
String receivedMessage = ((TextMessage) message).getText();
logger.info("Received message via JMS message Listener-Consumer: {}", receivedMessage);
if(receivedMessage.endsWith("35")) {
int i = num[5];
logger.info("Error processing the message");
}
}
catch (JMSException ex) {
logger.error("error processing incoming jms message-Consumer", ex);
}
}
else {
logger.warn("Received non text jms message-Consumer {}", message);
}
}
}
答案 0 :(得分:0)
我们一直在寻找类似的东西,我怀疑这个问题与Spring DefaultMessageListenerContainer处理事务的方式有关。特别是春季论坛的引用(这里是http://forum.spring.io/forum/other-spring-related/remoting/24208-what-s-the-best-practice-for-using-jms-in-spring):
关于事务管理:如果在DefaultMessageListenerContainer上指定“transactionManager”,它将在事务中包装其接收循环。这通常与JtaTransactionManager一起使用,其中没有事务资源实际绑定:它只是将线程(和侦听器的JMS会话)标记为“XA-active”并等待某些事情发生。对于任何体面的JTA提供商来说,这应该是非常有效的。
这意味着,如果你没有在DMLC上指定一个transactionManager,那么你实际上不会有一个包装onMessage的事务 - 即使它被注释为@Transactional。此外,虽然使用JtaTransactionManager是“典型”,但这可能是因为JMS事务通常是分布式的,并且需要XA。我相信如果你不需要XA,你也可以使用Spring的JmsTranactionManager。
因此,在您的情况下,请查看定义事务管理器bean,并将其作为DMLC配置中的transactionManager引用。