Search code examples
javaspringspring-bootrabbitmqspring-amqp

Spring AMQP - RabbitMQ connection is not created on application startup


I have a Spring Boot application and my goal is to declare queues, exchanges, and bindings on application startup. The application will produce messages to various queues there will be no consumers on the application.

I have included those dependencies on my pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.3.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.amqp</groupId>
    <artifactId>spring-rabbit</artifactId>
    <version>2.2.12.RELEASE</version>
</dependency>

my configuration class

@Configuration
public class RabbitConfiguration {

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory("myhost", 5672);
        connectionFactory.setUsername("example_name");
        connectionFactory.setPassword("example_pass");
        return connectionFactory;
    }

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

    @Bean
    public Queue declareQueue() {
        return new Queue("test_queue", true, false, false);
    }

    @Bean
    public DirectExchange declareDirectExchange() {
        return new DirectExchange("test_direct_exchange", true, false);
    }

    @Bean
    public Declarables declareBindings() {
        return new Declarables(
            new Binding("test_queue", DestinationType.QUEUE, "test_direct_exchange", "test_routing_key", null)
        );
    }
}

My problem is that queues, exchanges, and bindings are not created on the application startup. Spring boot does not even open the connection. The connection, queues, etc are created only when I produce messages to the queues.


Solution

  • If you want to force declaration during app startup and don't have any consumers, you can either add the actuator starter to the classpath, or simply create the shared connection yourself.

    @Bean
    ApplicationRunner runner(ConnectionFactory cf) {
        return args -> cf.createConnection().close();
    }
    

    This won't close the connection; if you want to do that, call cf.resetConnection().

    If you want the app to start if the broker is down, do something like this.

    @Bean
    ApplicationRunner runner(ConnectionFactory cf) {
        return args -> {
            boolean open = false;
            while(!open) {
                try {
                    cf.createConnection().close();
                    open = true;
                }
                catch (Exception e) {
                    Thread.sleep(5000);
                }
            }
        };
    }