使用RabbitMQ和JMS API进行事务管理

时间:2017-03-22 18:03:40

标签: java spring rabbitmq jms spring-jms

我正在尝试实现以下方案并使用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);
        }
    }

}

1 个答案:

答案 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引用。