Запрос/ответ RabbitMQ RabbitTemplate не настроен как слушатель

Я тестирую шаблон запроса/ответа с реализацией кролика Spring-AMQP, и я не могу заставить его работать...

У меня настроены следующие артефакты:

test_exchange с очередью приветствия. Ключ маршрутизации = приветствие
answer_exchange с очередью ответов. Ключ маршрутизации = ответы

@Bean
public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = 
            new CachingConnectionFactory("....IP of broker...");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    return connectionFactory;
}

@Bean
public Queue greeting() {
    return new Queue("greeting");
}

@Bean
public Queue replies() {
    return new Queue("replies");
}

MessageListener receiver() {
    return new MessageListenerAdapter(new RabbitMqReceiver(), "onMessage");
}

@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, Queue replies) {
    RabbitTemplate template = new RabbitTemplate(connectionFactory);
    template.setExchange("test_exchange");
    template.setRoutingKey("greeting");     
    template.setReplyAddress("reply_exchange"+"/"+replies.getName());
    template.setReplyTimeout(60000);
    return template;
}

@Bean
public SimpleMessageListenerContainer replyContainer(ConnectionFactory connectionFactory, 
        RabbitTemplate rabbitTemplate, Queue replies) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setMessageListener(rabbitTemplate);
    container.setQueues(replies);
    return container;
}

@Bean
public SimpleMessageListenerContainer serviceListenerContainer(
        ConnectionFactory connectionFactory) {
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueues(greeting());
    container.setMessageListener(receiver());
    return container;
}

Я следовал примеру на github, но он вылетает:

Вызвано: java.lang.IllegalStateException: RabbitTemplate не настроен как MessageListener — нельзя использовать «replyAddress»: answer_exchange/replies

В документации говорится:

Начиная с версии 1.5, RabbitTemplate определяет, настроен ли он как MessageListener для получения ответов. В противном случае попытки отправки и получения сообщений с адресом ответа завершатся с ошибкой IllegalStateException (поскольку ответы никогда не будут получены).

Это отлично, но как RabbitTemplate это делает? Как он определяет, настроен ли он как MessageListener?

заранее спасибо

PS: пришлите код:

public void send() {
    Message message = MessageBuilder.withBody("Payload".getBytes())
            .setContentType("text/plain")
            .build();
    Message reply = this.template.sendAndReceive(message);
    System.out.println("Reply from server is: "+new String(reply.getBody()));
}

person Tomas Kloucek    schedule 11.05.2016    source источник


Ответы (2)


Когда контейнер ответов запускается, он обнаруживает, что используется шаблон ListenerContainerAware, и вызывает expectedQueueNames() для извлечения очередей ответов (или null, если адрес ответа имеет форму exch/rk); если возвращается ненулевой результат, контейнер проверяет правильность очереди; если exch/rk является адресом ответа, вы получите это

logger.debug("Cannot verify reply queue because it has the form 'exchange/routingKey'");

Этот метод безоговорочно устанавливает логическое значение isListener, что позволяет избежать этого исключения. Итак, кажется, что контейнер не запустился до того, как вы отправили свое сообщение - вы отправляете его до того, как контекст будет полностью инициализирован?

Обратите внимание, что, поскольку RabbitMQ реализовал прямой ответ, как правило, больше нет необходимости использовать контейнер ответов (если только вам не нужны очереди ответов HA или вам не нужна явная очередь ответов по какой-либо другой причине). Прямой ответ устранил проблему с производительностью, из-за которой мы внедрили механизм контейнера ответов.

person Gary Russell    schedule 11.05.2016

Гэри, твоя интуиция, как всегда, была безупречна.

Я изменил свой код отправки с:

@SpringBootApplication
public class App 
{
    @Bean(initMethod="send")
    public RabbitMqSender sender() {
        final RabbitMqSender sender = new RabbitMqSender();
        return sender;
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(App.class, args);
    }

}

to:

@SpringBootApplication
public class App 
{   
public static void main(String[] args) throws Exception {
    final ConfigurableApplicationContext configAppContext =   SpringApplication.run(App.class, args);
    final RabbitMqSender sender = configAppContext.getBean(RabbitMqSender.class);
    sender.send();
}

}

чтобы обеспечить отправку, когда все bean-компоненты готовы, а запрос/ответ РАБОТАЕТ ОТЛИЧНО!

Да, обязательно попробую и паттерн Direct-TO.

Спасибо тебе Гэри за помощь.

С Уважением

Томас

person Tomas Kloucek    schedule 11.05.2016