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
pull/5289/head
Stephane Nicoll 9 years ago
parent 360caf3d97
commit 813d86e5e0

@ -20,6 +20,8 @@ import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
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.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -37,6 +39,9 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(EnableRabbit.class)
class RabbitAnnotationDrivenConfiguration {
@Autowired
private ObjectProvider<MessageConverter> messageConverter;
@Autowired
private RabbitProperties properties;
@ -44,6 +49,7 @@ class RabbitAnnotationDrivenConfiguration {
@ConditionalOnMissingBean
public SimpleRabbitListenerContainerFactoryConfigurer rabbitListenerContainerFactoryConfigurer() {
SimpleRabbitListenerContainerFactoryConfigurer configurer = new SimpleRabbitListenerContainerFactoryConfigurer();
configurer.setMessageConverter(this.messageConverter.getIfUnique());
configurer.setRabbitProperties(this.properties);
return configurer;
}

@ -1,5 +1,5 @@
/*
* 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");
* you may not use this file except in compliance with the License.
@ -25,6 +25,8 @@ import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
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.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -86,10 +88,18 @@ public class RabbitAutoConfiguration {
@Autowired
private ConnectionFactory connectionFactory;
@Autowired
private ObjectProvider<MessageConverter> messageConverter;
@Bean
@ConditionalOnMissingBean(RabbitTemplate.class)
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

@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.amqp;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.util.Assert;
/**
@ -29,8 +30,19 @@ import org.springframework.util.Assert;
*/
public final class SimpleRabbitListenerContainerFactoryConfigurer {
private MessageConverter messageConverter;
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.
* @param rabbitProperties the {@link RabbitProperties}
@ -51,6 +63,9 @@ public final class SimpleRabbitListenerContainerFactoryConfigurer {
Assert.notNull(factory, "Factory must not be null");
Assert.notNull(connectionFactory, "ConnectionFactory must not be null");
factory.setConnectionFactory(connectionFactory);
if (this.messageConverter != null) {
factory.setMessageConverter(this.messageConverter);
}
RabbitProperties.Listener listenerConfig = this.rabbitProperties.getListener();
factory.setAutoStartup(listenerConfig.isAutoStartup());
if (listenerConfig.getAcknowledgeMode() != null) {

@ -42,6 +42,7 @@ import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@ -128,6 +129,15 @@ public class RabbitAutoConfigurationTests {
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
public void testConnectionFactoryBackOff() {
load(TestConfiguration2.class);
@ -187,7 +197,8 @@ public class RabbitAutoConfigurationTests {
@Test
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.concurrency:5",
"spring.rabbitmq.listener.maxConcurrency:10",
@ -204,6 +215,8 @@ public class RabbitAutoConfigurationTests {
assertThat(dfa.getPropertyValue("maxConcurrentConsumers")).isEqualTo(10);
assertThat(dfa.getPropertyValue("prefetchCount")).isEqualTo(40);
assertThat(dfa.getPropertyValue("txSize")).isEqualTo(20);
assertThat(dfa.getPropertyValue("messageConverter")).isSameAs(
this.context.getBean("myMessageConverter"));
}
@Test
@ -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
@EnableRabbit
protected static class EnableRabbitConfiguration {

@ -3734,7 +3734,8 @@ directly into your own beans:
----
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
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
When the Rabbit infrastructure is present, any bean can be annotated with
`@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:

Loading…
Cancel
Save