Prevent @RabbitListener in spring-rabbit from trying to connect to server during integration test

Pete picture Pete · Jul 5, 2017 · Viewed 8.6k times · Source

I want to run some acceptance tests for my services that are using rabbitMq but I want to ignore all that require inter-service communication (amqp).

The problem however is that Spring tries to connect to the (non-exisiting) rabbit host on startup so it can register its consumers. It does that for each method that is annotated with @RabbitListener which can get quite annoying with the long timeout this has if I have more than one listener in my service.

How can I reduce this timeout or even prevent @RabbitListener connection all together?

Our (simplified) Rabbit Config:

@Configuration
@EnableRabbit
public class RabbitMqConfig {

    public RabbitMqConfig(
            @Value("${rabbitmq.host}") String rabbitHost,
            @Value("${rabbitmq.port}") int rabbitPort,
            @Value("${exchange.name}") String exchange) {
        this.rabbitHost = rabbitHost;
        this.rabbitPort = rabbitPort;
        this.exchange= exchange;
    }

  @Bean
  DirectExchange directExchangeBean() {
    return new DirectExchange(this.exchange, true, false);
  }

  @Bean
  public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitHost);
    connectionFactory.setPort(rabbitPort);
    return connectionFactory;
  }

  @Bean
  public RabbitTemplate rabbitTemplate() {
    return new RabbitTemplate(connectionFactory());
  }


  @Bean
  public Queue itemDoneQueue() {
    return new Queue(ITEM_DONE_QUEUENAME, true);
  }

  @Bean
  Binding itemDoneBinding() {
    return BindingBuilder.bind(itemDoneQueue()).to(directExchangeBean()).with(ITEM_DONE_KEY);
  }

}

Properties

rabbitmq.host=192.168.42.100
rabbitmq.port=5672
exchange.name=myExchange

The Listener:

  @RabbitListener(queues = ITEM_DONE_QUEUENAME)
  public void receiveMessageFromItemDoneQueue(String message) {
    // do the work
  }

The Test:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class}) 
public abstract class RabbitTest {

Really nothing special here. Obviously during testing the rabbit host is unavailable. That is fine. I want to ignore the fact. And quickly.

I've tried

spring.rabbitmq.connection-timeout=1

But that didn't change anything.

Using

spring.rabbitmq.listener.simple.auto-startup=false

neither does anything.

Using

spring.autoconfigure.exclude:org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration

just kills my application context loading with spring complaining about a NoSuchBeanDefinitionException: No bean named 'rabbitListenerContainerFactory' available

Any ideas? Thanks!

Answer

Volodymyr Belozorov picture Volodymyr Belozorov · Oct 22, 2018

If the property spring.rabbitmq.listener.simple.auto-startup=false does not have effect, you might be defining your own SimpleRabbitListenerContainerFactory bean

Check how this bean is defined in the RabbitAnnotationDrivenConfiguration.rabbitListenerContainerFactory()

The SimpleRabbitListenerContainerFactoryConfigurer binds together theSimpleRabbitListenerContainerFactory and properties defined in your application.properties (among other things)

If you use your own definition, then be sure to use something along the lines of

@Bean
SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
    SimpleRabbitListenerContainerFactoryConfigurer containerFactoryConfigurer, 
    ConnectionFactory connectionFactory) {

    SimpleRabbitListenerContainerFactory listenerContainerFactory =
            new SimpleRabbitListenerContainerFactory();
    containerFactoryConfigurer.configure(listenerContainerFactory, connectionFactory);

    return listenerContainerFactory;
}