如何使用SimpleMessageListenerContainerBean从RabbitMq队列以破坏性方式读取消息

如何使用SimpleMessageListenerContainerBean从RabbitMq队列以破坏性方式读取消息,rabbitmq,spring-amqp,spring-rabbit,Rabbitmq,Spring Amqp,Spring Rabbit,我需要一个帮助来实现SimpleMessageListenerContainer,使其能够在消息接收方读取消息后立即以非事务方式删除消息 在我的例子中,不管事务是否成功,放入队列的消息都会挂起(不在队列中),并在从队列读取的每个操作上重复处理。因此,放入队列的所有其他消息仍然不可访问,每次只重新处理第一条消息 另一件奇怪的事情是,我看不到消息在队列上登陆/排队,即Rabbit管理控制台上的队列深度从未改变,而只是消息速率在每次写入队列时都会发生跳跃 下面是我的Java配置的代码片段。如果有人能在

我需要一个帮助来实现SimpleMessageListenerContainer,使其能够在消息接收方读取消息后立即以非事务方式删除消息

在我的例子中,不管事务是否成功,放入队列的消息都会挂起(不在队列中),并在从队列读取的每个操作上重复处理。因此,放入队列的所有其他消息仍然不可访问,每次只重新处理第一条消息

另一件奇怪的事情是,我看不到消息在队列上登陆/排队,即Rabbit管理控制台上的队列深度从未改变,而只是消息速率在每次写入队列时都会发生跳跃

下面是我的Java配置的代码片段。如果有人能在这里指出错误,那将非常有帮助:-

@Configuration
@EnableJpaRepositories(basePackages={"com.xxx.muppets"})
public class MuppetMessageConsumerConfig {

private ApplicationContext applicationContext;
@Value("${rabbit.queue.name}")
private String queueName;

@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
}

@Bean
Queue queue() {
    return new Queue(queueName, false);
}

@Bean
TopicExchange exchange() {
    return new TopicExchange("spring-boot-exchange");
}

@Bean
Binding binding(Queue queue, TopicExchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with(queueName);
}

@Bean
MuppetMsgReceiver muppetMsgReceiver(){
    return new MuppetMsgReceiver();
}

@Bean
MessageListenerAdapter listenerAdapter(MuppetMsgReceiver muppetMsgReceiver){
    return new MessageListenerAdapter(muppetMsgReceiver, "receiveMessage");
}

@Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setAcknowledgeMode(NONE);
    container.setConnectionFactory(connectionFactory);
    container.setQueueNames(queueName);
    container.setMessageListener(listenerAdapter);
    return container;
}
}
我的消息接收器类别如下:

public class MuppetMsgReceiver {

private String muppetMessage;

private CountDownLatch countDownLatch;

public MuppetMsgReceiver() {
    this.countDownLatch = new CountDownLatch(1);
}

public MuppetMsgReceiver(CountDownLatch latch) {
    this.countDownLatch = latch;        
    CountDownLatch getCountDownLatch() {
    return countDownLatch;
}

public void receiveMessage(String receivedMessage) {
    countDownLatch.countDown();
    this.muppetMessage = receivedMessage;
}

public String getMuppetMessage() {
    return muppetMessage;
}
}

此完整代码基于Spring的版本,但由于从队列中进行非破坏性读取,因此没有帮助。

AcknowledgeMode=NONE
表示代理在消息发送给消费者时立即确认消息,而不是在消费者收到消息时确认消息,因此您观察到的行为对我来说毫无意义。使用此ack模式是非常不寻常的,但消息一经发送就会消失。这可能是您的代码有问题。跟踪日志记录将帮助您了解情况。

我完全同意这一点,Gary,这就是将Ack模式设置为None的全部原因。我想了解SimpleMessageListenerContainer的工作原理可能会对我有所帮助。我原以为它只在需要时才从队列中读取消息,但看起来好像接收方创建的bean在消息发布到代理上时就使用了消息。如果这种理解是正确的,您能帮助我吗?如果是,所有阅读信息都保存/存储在哪里?那个储藏室在我看来是一个没有冲洗的地方,它们不是“储藏”的;它们被写入
BlockingQueueConsumer
中的队列中(该队列的大小基于
预取计数
,以避免消费者无法跟上时出现OOM情况)。使用者线程删除每条消息并调用侦听器bean;在这种情况下,不可能重新传递消息。
BlockingQueueConsumer
是由RabbitMq管理的,在这种情况下,仍然无法确定为什么我的应用程序会出现错误,每次只能获取第一条消息。我仍然会用我的测试用例来给它一个外观和锻炼。如果您知道这种(错误)行为的任何可能原因,请务必让我知道。否。它是SMLC的内部。正如我所说的,打开跟踪调试。我碰巧深入研究了这个问题。这确实是我错误理解和实现消息接收器的方式。我曾希望仅在需要时从队列接收消息,但侦听器容器的实现不能满足需要,因此出现了问题。这一点现在通过一个变通方法得到了解决。然而,目前我遇到了另一个困惑,即消息是按照后进先出顺序读取的,而不是队列中预期的先进先出顺序。这是如何配置的,以便我只接收FIFO中的消息?