Search code examples
rabbitmqspring-amqpspring-rabbit

Using multiple rabbit listener annotations. Only one is registering. Other throws exception


I created two queue configurations each having its own @RabbitListener annotated methods.

@Configuration
@EnableRabbit
public class TestQueue extends QueueConfiguration {

public String getQueueName() {
   return "testQueue";
}

public String getRoutingKey() {
   return "testKey";
}

@RabbitListener(queues = "testQueue")
public void receive(Message message) { ... }

}

Another queue configuration

@Configuration
@EnableRabbit
public class AnotherTestQueue extends QueueConfiguration {

public String getQueueName() {
   return "anotherTestQueue";
}

public String getRoutingKey() {
   return "anotherTestKey";
}

@RabbitListener(queues = "anotherTestQueue")
public void receive(Message message) { ... }

}

Here is the base queue configuration where I create queue, exchange and binding:

public abstract class QueueConfiguration {

@Bean
public Queue mainQueue() {
   return new Queue(getQueueName());
}

@Bean
public DirectExchange mainExchange() {
   return new DirectExchange("main.exchange");
}

@Bean
public Binding mainExchangeBinding() {
   return BindingBuilder.build(mainQueue()).to(mainExchange()).with(getRoutingKey());
}

// getQueueName() and getRoutingKey() are abstract methods

}

Now the common configuration class

@Configuration
public class CommonConfiguration {

@Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory,
            WfmMessageListener listener) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        factory.setAdviceChain(listener);
        return factory;
    }

@Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }
}

When I start the app, I get the following error:

Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method(reply-code=404, reply-text=NOT_FOUND - no queue 'testQueue' in vhost '/', class-id=50, method-id=10) at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:505) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:336) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:143) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:90) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:634) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47) ~[amqp-client-4.0.3.jar:4.0.3] at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:572) ~[amqp-client-4.0.3.jar:4.0.3]

I tried with just one queue configuration, it works fine! When I have more than one rabbit listener, it is throwing this error. Kindly help.


Solution

  • public abstract class QueueConfiguration

    The Queue definition @Beans have to have unique bean names (the bean name is the method name, by default); since your config classes both subclass QueueConfiguration you will end up with one @Bean called mainQueue. The first definition is overridden by the second.

    You need to move that @Bean into the subclasses and give them unique bean names

    public abstract Queue mainQueue();
    
    @Override
    @Bean("someBeanName")
    public Queue mainQueue() {
       return new Queue(getQueueName());
    }
    
    @Override
    @Bean("someOtherBeanName")
    public Queue mainQueue() {
       return new Queue(getQueueName());
    }