【问题标题】:How to not acknowledge only one message with Spring-JMS?如何不使用 Spring-JMS 只确认一条消息?
【发布时间】:2014-02-26 10:16:23
【问题描述】:

有一个类 'MyConsumer' 从队列接收消息并处理它们。有两个要求:

  1. 如果有消息包含无效内容,MyConsumer 不应确认,但可以处理以后的消息
  2. MyConsumer 重启后,未消费的消息将再次投递

我尝试使用 spring-jms,支持 listener-container,但找不到符合第一个要求的解决方案。

我的代码:

<amq:queue id="destination" physicalName="org.springbyexample.jms.test"/>

<amq:connectionFactory id="jmsFactory" brokerURL="tcp://localhost:11111"/>

<bean id="jmsConsumerConnectionFactory"
      class="org.springframework.jms.connection.SingleConnectionFactory"
      p:targetConnectionFactory-ref="jmsFactory"/>

<bean id="jmsConsumerTemplate" class="org.springframework.jms.core.JmsTemplate"
      p:connectionFactory-ref="jmsConsumerConnectionFactory"
      p:defaultDestination-ref="destination"/>

<bean id="jmsMessageListener" class="test.MyConsumer"/>
<bean id="errorHandler" class="test.MyErrorHandler"/>

<jms:listener-container container-type="default"
                        connection-factory="jmsConsumerConnectionFactory"
                        error-handler="errorHandler"
                        acknowledge="client">
    <jms:listener destination="org.springbyexample.jms.test" ref="jmsMessageListener"/>
</jms:listener-container>

班级MyConsumer:

@Override
public void onMessage(Message message) {
    TextMessage textMessage = (TextMessage) message;
    try {
        System.out.println("!!!!!!!!! get message: " + textMessage.getText());
    } catch (JMSException e) {
        e.printStackTrace();
    }
    if (theNumberOfMessageIs(3)) {
        throw new RuntimeException("something is wrong");
    }
}

你可能注意到listener-container中的acknowledgeclient,实际上它有3个值:

  1. 自动(默认)
  2. 客户
  3. 已成交

我尝试了所有这些,但没有一个符合我的要求。我的测试场景:

  1. 生产者将 3 条消息放入队列
  2. 启动一个线程来监控队列中的消息计数,当计数发生变化时,打印出来
  3. 启动消费者,它将接收来自队列的消息,并处理它们
  4. 稍等片刻,将另外 3 条消息放入队列

对于auto

MyConsumer 在收到每条消息后都会确认,无论是否抛出异常

对于client

只有在onMessage 中没有抛出异常时,MyConsumer 才会确认。对于第 3 条消息,它会抛出异常,队列中会有一条消息未消费。但是当它得到第 4 条消息并且没有抛出异常时,队列中的第 3 条消息将消失

对于transacted

如果在 MyConsumer 中抛出异常,消息将不会被确认并被重新发送多次。之后,消息从队列中消失

但没有一个符合要求1。

我想知道:我是否需要寻找除Spring-jms之外的其他解决方案,或者我的用法不正确?

【问题讨论】:

  • 嗨@Freewind,你达到你的要求了吗?

标签: java jms spring-jms


【解决方案1】:

auto DefaultMessageListenerContainer 真的是为交易而设计的 - 正如你所发现的,使用自动,消息总是得到确认。您可以使用SimpleMessagseListenerContainer,它可以按照您的意愿工作,但它有其他限制;请参阅 JavaDocs。

client 这就是 JMS 在您确认 #4 时的工作方式,#3 也会自动确认 - 请参阅 Message JavaDocs。客户端模式用于减少确认流量(例如,每 10 条消息确认一次)。

transacted这是broker的一个功能,你可以配置AMQ在重试几次后将坏消息发送到死信队列。

您需要一些过程将消息从 DLQ 移回主队列以供稍后重试(可能在重新启动时的初始化期间)。

【讨论】:

    【解决方案2】:

    使用 WMQ,您可以使用 BackOut 功能使用 BOTHRESH 和 BOQNAME QUEUE 配置参数来实现要求,其中 BOTHRESH 定义您将尝试使用该消息的次数,并且在该参数之后 BOQNAME 定义您要重新发送的消息的 QUEUE 名称。在这种情况下,您可以使用 DLQ QUEUE,您可以在一段时间后将消息移动到主 QUEUE,或者将主 QUEUE 用作 DLQ QUEUE,从而在您的消费者中启用消息轮换。 希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2014-05-06
      • 2012-01-13
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      • 2012-11-26
      • 1970-01-01
      • 2015-12-02
      相关资源
      最近更新 更多