如何手动从RabbitMQ Spring中提取消息

时间:2016-10-17 18:59:49

标签: spring-amqp spring-rabbit spring-rabbitmq

我需要从RabbitMQ队列手动提取记录,而不是自动提取。以下是我创建的内容。但是,我想知道Spring / RabbitMQ是否有更好的方法呢?

您会注意到channel.basicAck和channel.basicNack的使用。我已将这些放置在可以确认/ NotAcknowledge的位置,如果/当消费者抛出异常时,记录可以保持排队。

我会使用RabbitTemplate.receiveAndConvert,但这会自动确认记录,即使可能有原因不应该被承认。

import java.util.Properties;
import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.ChannelCallback;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.DefaultMessagePropertiesConverter;
import org.springframework.amqp.rabbit.support.MessagePropertiesConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.GetResponse;

@Service
public class RabbitAdminServices {

    private static final Logger logger = LoggerFactory.getLogger(RabbitAdminServices.class);

    @Autowired
    AmqpAdmin rabbitAdmin;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    MessageConverter messageConverter;

    private volatile MessagePropertiesConverter messagePropertiesConverter = new DefaultMessagePropertiesConverter();

    public int getCount(String queueName) {

        Properties properties = rabbitAdmin.getQueueProperties(queueName);
        return (Integer)properties.get(RabbitAdmin.QUEUE_MESSAGE_COUNT);
    }

    public <T> void processQueue(String queueName, Integer count, Class<T> clazz, Consumer<T> consumer) {

        int reprocessCount = getCount(queueName);
        int requestCount = reprocessCount;
        if(count != null) {
            requestCount = count;
        }
        for(int i = 0; i < reprocessCount && i < requestCount; i++) {
            rabbitTemplate.execute(new ChannelCallback<T>() {

                @Override
                public T doInRabbit(Channel channel) throws Exception {
                    GetResponse response = channel.basicGet(queueName, false);
                    T result = null;
                    try {
                        MessageProperties messageProps = messagePropertiesConverter.toMessageProperties(response.getProps(), response.getEnvelope(), "UTF-8");
                        if(response.getMessageCount() >= 0) {
                            messageProps.setMessageCount(response.getMessageCount());
                        }
                        Message message = new Message(response.getBody(), messageProps);
                        result = (T)messageConverter.fromMessage(message);
                        consumer.accept(result);
                        channel.basicAck(response.getEnvelope().getDeliveryTag(), false);
                    }
                    catch(Exception e) {
                        channel.basicNack(response.getEnvelope().getDeliveryTag(), false, true);
                    }
                    return result;
                }
            });

        }
    }
}

1 个答案:

答案 0 :(得分:1)

您的解决方案与模板的当前状态是正确的;我们应该考虑将重载方法添加到RabbitTemplate,类似

<T> void template.receiveAndConvert(..., Class<T> clazz, Consumer<T> consumer);

并根据消费者是否抛出异常来获得模板ack / nack。这样可以避免在代码中进行转换。