获得一个简单的Spring JMS客户端确认可以工作

时间:2012-02-01 12:04:06

标签: spring jms activemq

刚刚开始让我的目标让JMS ActiveMQ Acknowledgements在Spring工作。到目前为止,我有一个消费者正常工作,但有一个例外,当我不确认消息时,它仍然从队列中取出(我希望它留在那里或以死信队列结束)。

        

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">

    <!-- A JMS connection factory for ActiveMQ -->
    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
    p:brokerURL="failover://(tcp://jms1:61616,tcp://jms2:61616)?randomize=false&amp;jms.redeliveryPolicy.maximumRedeliveries=5" />

    <!-- A POJO that implements the JMS message listener -->
    <bean id="simpleMessageListener" class="com.company.ConsumerClass" />

    <!-- A JMS namespace aware Spring configuration for the message listener container -->
    <jms:listener-container
            container-type="default"
            connection-factory="connectionFactory"
            acknowledge="client"
            concurrency="10-50"
            cache="consumer">
        <jms:listener destination="someQueue" ref="simpleMessageListener" method="onMessage" />
    </jms:listener-container>
</beans>

在ConsumerClass中,我的简单消费者看起来像这样:

@Override public final void onMessage(Message message) {
    Object postedMessage = null;
    try {
        postedMessage = ((ObjectMessage) message).getObject();

        if (postedMessage.getClass() == SomeMessageType.class) {
            try {
                //Some logic here

                message.acknowledge();
                return; //Success Here
            } catch (MyException e) {
                logger.error("Could not process message, but as I didn't call acknowledge I expect it to end up in the dead message queue");
            }
        }
    } catch (JMSException e) {
        logger.error("Error occurred pulling Message from Queue", e);
    }

    //Also worth noting, if I throw new RuntimeException("Aww Noos"); here then it won't take it from the queue, but it won't get consumed (or end up as dead letter)...
}

6 个答案:

答案 0 :(得分:18)

阅读本文档:Spring JMS容器不使用message.acknowledge()

侦听器容器提供以下消息确认选项:

  

“sessionAcknowledgeMode”设置为“AUTO_ACKNOWLEDGE”(默认值):在侦听器执行之前自动确认消息;如果抛出异常,则不予以重新发送   “sessionAcknowledgeMode”设置为“CLIENT_ACKNOWLEDGE”:成功侦听器执行后自动确认消息;如果抛出异常,则不予以重新发送   “sessionAcknowledgeMode”设置为“DUPS_OK_ACKNOWLEDGE”:在侦听器执行期间或之后的延迟消息确认;如果抛出异常,可能会重新发送   “sessionTransacted”设置为“true”:成功监听器执行后的事务确认;在发生例外的情况下保证重新发送。

答案 1 :(得分:7)

我在http://ourcraft.wordpress.com/2008/07/21/simple-jms-transaction-rollbacks-work/

找到答案

如果你更改acknowledge =“transacted”并确保你抛出新的RuntimeException(“消息无法消耗。回滚事务”),它似乎运行良好;在OnMessage()例程的末尾。

仍然不知道承认=“客户”实现了什么

答案 2 :(得分:5)

现在Spring提供了对普通JMS消息监听器的良好包装。

参见AbstractMessageListenerContainer的JavaDocs。

  

"sessionAcknowledgeMode"设置为"CLIENT_ACKNOWLEDGE":成功侦听器执行后自动确认消息;在抛出用户异常的情况下以及在其他侦听器执行中断的情况下(例如JVM死亡),尽力而为重新传递。

因此,当您定义@JmsListener方法时,确认会在成功完成后自动发送,但您可以抛出异常以再次接收消息。

答案 3 :(得分:-1)

在我的实践中,客户确认很少使用。典型设置是自动确认,因此如果您的代码通常从onMessage()返回(没有异常),则会自动确认消息。如果您的代码从onMessage()抛出异常,则无法确认,并且通常会将消息重新传递到预先配置的次数,之后通常会将其丢弃或放入死信息队列中。

在您的情况下,从JMS服务器的角度来看,它看起来像客户端要求消息但从未确认,因此它仍然由客户端“处理”。在这种情况下,消息对于同一队列中的其他消费者是不可见的,因此您可能会得到消息“脱离队列”的印象,而事实上它仍然存在。显然,你也不会在死信息队列中看到这样的消息。

我建议你阅读JMS规范,以便清楚地了解不同的确认模式。

答案 4 :(得分:-1)

在您的消费者中对消息调用acknowledge()方法。

  

请考虑以下情形:应用程序接收但不确认消息。应用程序收到后续消息并对其进行确认。前一条消息怎么了?前一条消息也被认为是公认的。通常,确认特定消息会确认会话接收的所有先前消息。在上面的输出中,只显示消息5。消息5之前的所有消息都被隐式确认。消息5之后的消息未得到确认。

有关详细信息,请参阅this article

另请参阅此文章Sun Java System Message Queue 4.3 Developer's Guide for Java Clients

答案 5 :(得分:-2)

使用以下代码。

<bean id="{containerName}"  class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="connectionFactory" ref={connectionFactoryBean} />
    <property name="destinationName" ref="{queue}" />
    <property name="messageListener" ref="{listner}" />
    <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>
</bean>