Search code examples
rabbitmqamqpspring-rabbit

How to create queues and exchanges at application start?


I'm using RabbitMQ and Spring Boot and I want to create all queues and exchanges declared when application starts.

I have one exchange and two queues binding to it. Also I have another queue without binding to any exchange.

The exchange declaration is like this:

@Bean
TopicExchange exchange() {
    return new TopicExchange(name, false, false);
}

And the queues:

@Bean
Queue queue1() {
    return new Queue(name, false);
}

@Bean
Binding bindingLogger(Queue queue1, TopicExchange exchange) {
    return BindingBuilder.bind(queue1).to(exchange).with("routingKey");
}

And the queue without binding:

@Bean
Queue queue2() {
    return new Queue(name, false);
}

Also I have used @Component tag in the classes.

I think this is ok because if I add a "dummy" @RabbitListener all queues and the exchange are created. Adding something like this:

@Component
public class DummyListener {
    @RabbitListener(queues = {FAKE_QUEUE_NAME})
    public void dummyMethod(Message message, Channel channel) {
        // The code never will enter here because nobody are going to
        // insert data into the queue.
        // This method is only to create queues and exchange on init
    }
}

But I think this is a dirty solution, is neccesary create a listener which never will be triggered and a queue which never will be used.

And, as I said before, the queues and exchange declarations works perfectly and are created when project start if this "dummy listener" is implemented.

So, how can I create the exchange and queues (if not exists) when start the application? Is there a more elegant way?

I've read about rabbitAdmin but I think this is to create a new queue at runtime (actually I don't know if I have to manage in a different way at start and at runtime)

Thanks in advance.


Solution

  • Those Declarables are populated into RabbitMQ broker when the connection is opened. This really happens with the listener container starting from that @RabbitListener.

    All the hard logic is done from the mentioned RabbitAdmin:

    /**
     * If {@link #setAutoStartup(boolean) autoStartup} is set to true, registers a callback on the
     * {@link ConnectionFactory} to declare all exchanges and queues in the enclosing application context. If the
     * callback fails then it may cause other clients of the connection factory to fail, but since only exchanges,
     * queues and bindings are declared failure is not expected.
     *
     * @see InitializingBean#afterPropertiesSet()
     * @see #initialize()
     */
    @Override
    public void afterPropertiesSet() {
    

    Another point of connection is of course a RabbitTemplate when you produce the message into an exchange.

    If you really are not going to do any consumption or production, you can consider to inject an AmqpAdmin into your service and call its initialize() when you need:

    /**
     * Declares all the exchanges, queues and bindings in the enclosing application context, if any. It should be safe
     * (but unnecessary) to call this method more than once.
     */
    @Override // NOSONAR complexity
    public void initialize() {
    

    However from here is the question: what is the point to have all those declarations in your application if you are not going to use them in the further logic. Looks like a mix of concerns and abuse of AMQP API. Better to have those entities declared outside of your application, e.g. using RabbitMQ Management console or command line util...