Commit 813d86e5 authored by Stephane Nicoll's avatar Stephane Nicoll

Auto-configure Rabbit MessageConverter

If a `MessageConverter` bean is available, we now associate it to the
created `RabbitTemplate` and `RabbitListenerContainerFactory`. That way,
registering a custom `MessageConverter` is all that's needed.

The Rabbit auto-configuration is now using the new `ObjectProvider` that
offers a nicer API to detect if a primary candidate is available for
optional collaborators.

Closes gh-5088
parent 360caf3d
...@@ -20,6 +20,8 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit; ...@@ -20,6 +20,8 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils; import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
...@@ -37,6 +39,9 @@ import org.springframework.context.annotation.Configuration; ...@@ -37,6 +39,9 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(EnableRabbit.class) @ConditionalOnClass(EnableRabbit.class)
class RabbitAnnotationDrivenConfiguration { class RabbitAnnotationDrivenConfiguration {
@Autowired
private ObjectProvider<MessageConverter> messageConverter;
@Autowired @Autowired
private RabbitProperties properties; private RabbitProperties properties;
...@@ -44,6 +49,7 @@ class RabbitAnnotationDrivenConfiguration { ...@@ -44,6 +49,7 @@ class RabbitAnnotationDrivenConfiguration {
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SimpleRabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactoryConfigurer() { public SimpleRabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactoryConfigurer() {
SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer(); SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer();
configurer.setMessageConverter(this.messageConverter.getIfUnique());
configurer.setRabbitProperties(this.properties); configurer.setRabbitProperties(this.properties);
return configurer; return configurer;
} }
......
/* /*
* Copyright 2012-2015 the original author or authors. * Copyright 2012-2016 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -25,6 +25,8 @@ import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean; ...@@ -25,6 +25,8 @@ import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate; import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
...@@ -86,10 +88,18 @@ public class RabbitAutoConfiguration { ...@@ -86,10 +88,18 @@ public class RabbitAutoConfiguration {
@Autowired @Autowired
private ConnectionFactory connectionFactory; private ConnectionFactory connectionFactory;
@Autowired
private ObjectProvider<MessageConverter> messageConverter;
@Bean @Bean
@ConditionalOnMissingBean(RabbitTemplate.class) @ConditionalOnMissingBean(RabbitTemplate.class)
public RabbitTemplate rabbitTemplate() { public RabbitTemplate rabbitTemplate() {
return new RabbitTemplate(this.connectionFactory); RabbitTemplate rabbitTemplate = new RabbitTemplate(this.connectionFactory);
MessageConverter messageConverter = this.messageConverter.getIfUnique();
if (messageConverter != null) {
rabbitTemplate.setMessageConverter(messageConverter);
}
return rabbitTemplate;
} }
@Configuration @Configuration
......
...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.amqp; ...@@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.amqp;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
...@@ -29,8 +30,19 @@ import org.springframework.util.Assert; ...@@ -29,8 +30,19 @@ import org.springframework.util.Assert;
*/ */
public final class SimpleRabbitListenerContainerFactoryConfigurer { public final class SimpleRabbitListenerContainerFactoryConfigurer {
private MessageConverter messageConverter;
private RabbitProperties rabbitProperties; private RabbitProperties rabbitProperties;
/**
* Set the {@link MessageConverter} to use or {@code null} if the out-of-the-box
* converter should be used.
* @param messageConverter the {@link MessageConverter}
*/
void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
/** /**
* Set the {@link RabbitProperties} to use. * Set the {@link RabbitProperties} to use.
* @param rabbitProperties the {@link RabbitProperties} * @param rabbitProperties the {@link RabbitProperties}
...@@ -51,6 +63,9 @@ public final class SimpleRabbitListenerContainerFactoryConfigurer { ...@@ -51,6 +63,9 @@ public final class SimpleRabbitListenerContainerFactoryConfigurer {
Assert.notNull(factory, "Factory must not be null"); Assert.notNull(factory, "Factory must not be null");
Assert.notNull(connectionFactory, "ConnectionFactory must not be null"); Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
factory.setConnectionFactory(connectionFactory); factory.setConnectionFactory(connectionFactory);
if (this.messageConverter != null) {
factory.setMessageConverter(this.messageConverter);
}
RabbitProperties.Listener listenerConfig = this.rabbitProperties.getListener(); RabbitProperties.Listener listenerConfig = this.rabbitProperties.getListener();
factory.setAutoStartup(listenerConfig.isAutoStartup()); factory.setAutoStartup(listenerConfig.isAutoStartup());
if (listenerConfig.getAcknowledgeMode() != null) { if (listenerConfig.getAcknowledgeMode() != null) {
......
...@@ -42,6 +42,7 @@ import org.springframework.boot.test.EnvironmentTestUtils; ...@@ -42,6 +42,7 @@ import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
...@@ -128,6 +129,15 @@ public class RabbitAutoConfigurationTests { ...@@ -128,6 +129,15 @@ public class RabbitAutoConfigurationTests {
assertThat(connectionFactory.getVirtualHost()).isEqualTo("/"); assertThat(connectionFactory.getVirtualHost()).isEqualTo("/");
} }
@Test
public void testRabbitTemplateMessageConverters() {
load(MessageConvertersConfiguration.class);
RabbitTemplate rabbitTemplate = this.context
.getBean(RabbitTemplate.class);
assertThat(rabbitTemplate.getMessageConverter()).isSameAs(
this.context.getBean("myMessageConverter"));
}
@Test @Test
public void testConnectionFactoryBackOff() { public void testConnectionFactoryBackOff() {
load(TestConfiguration2.class); load(TestConfiguration2.class);
...@@ -187,7 +197,8 @@ public class RabbitAutoConfigurationTests { ...@@ -187,7 +197,8 @@ public class RabbitAutoConfigurationTests {
@Test @Test
public void testRabbitListenerContainerFactoryWithCustomSettings() { public void testRabbitListenerContainerFactoryWithCustomSettings() {
load(TestConfiguration.class, "spring.rabbitmq.listener.autoStartup:false", load(MessageConvertersConfiguration.class,
"spring.rabbitmq.listener.autoStartup:false",
"spring.rabbitmq.listener.acknowledgeMode:manual", "spring.rabbitmq.listener.acknowledgeMode:manual",
"spring.rabbitmq.listener.concurrency:5", "spring.rabbitmq.listener.concurrency:5",
"spring.rabbitmq.listener.maxConcurrency:10", "spring.rabbitmq.listener.maxConcurrency:10",
...@@ -204,6 +215,8 @@ public class RabbitAutoConfigurationTests { ...@@ -204,6 +215,8 @@ public class RabbitAutoConfigurationTests {
assertThat(dfa.getPropertyValue("maxConcurrentConsumers")).isEqualTo(10); assertThat(dfa.getPropertyValue("maxConcurrentConsumers")).isEqualTo(10);
assertThat(dfa.getPropertyValue("prefetchCount")).isEqualTo(40); assertThat(dfa.getPropertyValue("prefetchCount")).isEqualTo(40);
assertThat(dfa.getPropertyValue("txSize")).isEqualTo(20); assertThat(dfa.getPropertyValue("txSize")).isEqualTo(20);
assertThat(dfa.getPropertyValue("messageConverter")).isSameAs(
this.context.getBean("myMessageConverter"));
} }
@Test @Test
...@@ -325,6 +338,22 @@ public class RabbitAutoConfigurationTests { ...@@ -325,6 +338,22 @@ public class RabbitAutoConfigurationTests {
} }
@Configuration
protected static class MessageConvertersConfiguration {
@Bean
@Primary
public MessageConverter myMessageConverter() {
return mock(MessageConverter.class);
}
@Bean
public MessageConverter anotherMessageConverter() {
return mock(MessageConverter.class);
}
}
@Configuration @Configuration
@EnableRabbit @EnableRabbit
protected static class EnableRabbitConfiguration { protected static class EnableRabbitConfiguration {
......
...@@ -3734,7 +3734,8 @@ directly into your own beans: ...@@ -3734,7 +3734,8 @@ directly into your own beans:
---- ----
NOTE: {spring-amqp-javadoc}/rabbit/core/RabbitMessagingTemplate.{dc-ext}[`RabbitMessagingTemplate`] NOTE: {spring-amqp-javadoc}/rabbit/core/RabbitMessagingTemplate.{dc-ext}[`RabbitMessagingTemplate`]
can be injected in a similar manner. can be injected in a similar manner. If a `MessageConverter` bean is defined, it is associated
automatically to the auto-configured `AmqpTemplate`.
Any `org.springframework.amqp.core.Queue` that is defined as a bean will be automatically Any `org.springframework.amqp.core.Queue` that is defined as a bean will be automatically
used to declare a corresponding queue on the RabbitMQ instance if necessary. used to declare a corresponding queue on the RabbitMQ instance if necessary.
...@@ -3745,7 +3746,8 @@ used to declare a corresponding queue on the RabbitMQ instance if necessary. ...@@ -3745,7 +3746,8 @@ used to declare a corresponding queue on the RabbitMQ instance if necessary.
==== Receiving a message ==== Receiving a message
When the Rabbit infrastructure is present, any bean can be annotated with When the Rabbit infrastructure is present, any bean can be annotated with
`@RabbitListener` to create a listener endpoint. If no `RabbitListenerContainerFactory` `@RabbitListener` to create a listener endpoint. If no `RabbitListenerContainerFactory`
has been defined, a default one is configured automatically. has been defined, a default one is configured automatically. If a `MessageConverter`
beans is defined, is is associated automatically to the default factory.
The following component creates a listener endpoint on the `someQueue` queue: The following component creates a listener endpoint on the `someQueue` queue:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment