RabbitMQ请求/响应“RabbitTemplate未配置为侦听器”

时间:2016-05-11 08:17:12

标签: rabbitmq spring-rabbitmq

我正在使用Spring-AMQP rabbitmq实现测试请求/响应模式,我无法使其工作......

我已经配置了以下工件:

带问候队列的test_exchange。路由键=问候语 带有回复队列的reply_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':reply_exchange / reply

文档说:

  

从版本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()));
}

2 个答案:

答案 0 :(得分:1)

当回复容器启动时,它会检测到模板为ListenerContainerAware并调用expectedQueueNames()来检索回复队列(如果replyAddress的格式为exch / rk,则为null);如果返回非null结果,则容器检查队列是否正确;如果exch / rk是回复地址,你会得到这个

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

此方法无条件地设置isListener布尔值,以避免该异常。因此,在您发送邮件之前,似乎容器尚未启动 - 您是在上下文完全初始化之前发送的吗?

请注意,由于RabbitMQ实现了直接回复,因此通常不再需要使用回复容器(除非您需要HA回复队列或由于其他原因需要显式回复队列)。直接回复 - 消除了促使我们实施回复容器机制的性能问题。

答案 1 :(得分:0)

加里,你的直觉一如既往地完美无缺。

我改变了我的发送代码:

@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);
    }

}

为:

@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模式。

谢谢你的帮助。

问候

托马斯