From 774941e9585d6e0c14e9c8c27c06e532c76c4f3e Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Tue, 10 Aug 2021 09:36:48 -0400 Subject: [PATCH 1/2] Apply container customizer bean to AMQP MessageListenerContainer See gh-27625 --- .../RabbitAnnotationDrivenConfiguration.java | 16 +++++- .../amqp/RabbitAutoConfigurationTests.java | 50 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java index 5cad42cfc3e..c959a22b18b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java @@ -19,10 +19,13 @@ package org.springframework.boot.autoconfigure.amqp; import java.util.stream.Collectors; import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.amqp.rabbit.config.ContainerCustomizer; import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; 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.rabbit.listener.DirectMessageListenerContainer; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.retry.MessageRecoverer; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.ObjectProvider; @@ -48,14 +51,23 @@ class RabbitAnnotationDrivenConfiguration { private final ObjectProvider retryTemplateCustomizers; + private final ObjectProvider> simpleContainerCustomizer; + + private final ObjectProvider> directContainerCustomizer; + private final RabbitProperties properties; RabbitAnnotationDrivenConfiguration(ObjectProvider messageConverter, ObjectProvider messageRecoverer, - ObjectProvider retryTemplateCustomizers, RabbitProperties properties) { + ObjectProvider retryTemplateCustomizers, + ObjectProvider> simpleContainerCustomizer, + ObjectProvider> directContainerCustomizer, + RabbitProperties properties) { this.messageConverter = messageConverter; this.messageRecoverer = messageRecoverer; this.retryTemplateCustomizers = retryTemplateCustomizers; + this.simpleContainerCustomizer = simpleContainerCustomizer; + this.directContainerCustomizer = directContainerCustomizer; this.properties = properties; } @@ -79,6 +91,7 @@ class RabbitAnnotationDrivenConfiguration { SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); configurer.configure(factory, connectionFactory); + this.simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer); return factory; } @@ -101,6 +114,7 @@ class RabbitAnnotationDrivenConfiguration { DirectRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory(); configurer.configure(factory, connectionFactory); + this.directContainerCustomizer.ifUnique(factory::setContainerCustomizer); return factory; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index dba9917b9e6..31a523435cf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -37,7 +37,9 @@ import org.springframework.amqp.core.AcknowledgeMode; import org.springframework.amqp.core.AmqpAdmin; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.amqp.rabbit.config.AbstractRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.config.ContainerCustomizer; import org.springframework.amqp.rabbit.config.DirectRabbitListenerContainerFactory; import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils; import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory; @@ -49,7 +51,9 @@ import org.springframework.amqp.rabbit.connection.ConnectionNameStrategy; 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.rabbit.listener.DirectMessageListenerContainer; import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.retry.MessageRecoverer; import org.springframework.amqp.support.converter.MessageConverter; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -849,6 +853,20 @@ class RabbitAutoConfigurationTests { }); } + @Test + void simpleContainerCustomizer() { + this.contextRunner.withUserConfiguration(SimpleContainerCustomizerConfiguration.class).run( + (context) -> assertThat(context.getBean(SimpleContainerCustomizerConfiguration.class).customizerCalled) + .isTrue()); + } + + @Test + void directContainerCustomizer() { + this.contextRunner.withUserConfiguration(DirectContainerCustomizerConfiguration.class) + .withPropertyValues("spring.rabbitmq.listener.type:direct").run((context) -> assertThat( + context.getBean(DirectContainerCustomizerConfiguration.class).customizerCalled).isTrue()); + } + private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory(AssertableApplicationContext context) { CachingConnectionFactory connectionFactory = context.getBean(CachingConnectionFactory.class); return connectionFactory.getRabbitConnectionFactory(); @@ -1113,4 +1131,36 @@ class RabbitAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + static class SimpleContainerCustomizerConfiguration { + + boolean customizerCalled; + + @RabbitListener(queues = "test", autoStartup = "false") + void listen(String in) { + } + + @Bean + ContainerCustomizer customizer() { + return (container) -> this.customizerCalled = true; + } + + } + + @Configuration(proxyBeanMethods = false) + static class DirectContainerCustomizerConfiguration { + + boolean customizerCalled; + + @RabbitListener(queues = "test", autoStartup = "false") + void listen(String in) { + } + + @Bean + ContainerCustomizer customizer() { + return (container) -> this.customizerCalled = true; + } + + } + } From 0ed9085ba2a2c35a6bdc593b249250c1124929d3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 11 Aug 2021 11:19:04 +0100 Subject: [PATCH 2/2] Polish "Apply container customizer bean to AMQP MessageListenerContainer" See gh-27625 --- .../RabbitAnnotationDrivenConfiguration.java | 21 +++------ .../amqp/RabbitAutoConfigurationTests.java | 45 ++++++++++--------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java index c959a22b18b..3a2a6bceb75 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/amqp/RabbitAnnotationDrivenConfiguration.java @@ -51,23 +51,14 @@ class RabbitAnnotationDrivenConfiguration { private final ObjectProvider retryTemplateCustomizers; - private final ObjectProvider> simpleContainerCustomizer; - - private final ObjectProvider> directContainerCustomizer; - private final RabbitProperties properties; RabbitAnnotationDrivenConfiguration(ObjectProvider messageConverter, ObjectProvider messageRecoverer, - ObjectProvider retryTemplateCustomizers, - ObjectProvider> simpleContainerCustomizer, - ObjectProvider> directContainerCustomizer, - RabbitProperties properties) { + ObjectProvider retryTemplateCustomizers, RabbitProperties properties) { this.messageConverter = messageConverter; this.messageRecoverer = messageRecoverer; this.retryTemplateCustomizers = retryTemplateCustomizers; - this.simpleContainerCustomizer = simpleContainerCustomizer; - this.directContainerCustomizer = directContainerCustomizer; this.properties = properties; } @@ -88,10 +79,11 @@ class RabbitAnnotationDrivenConfiguration { @ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = "type", havingValue = "simple", matchIfMissing = true) SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory( - SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { + SimpleRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory, + ObjectProvider> simpleContainerCustomizer) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); configurer.configure(factory, connectionFactory); - this.simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer); + simpleContainerCustomizer.ifUnique(factory::setContainerCustomizer); return factory; } @@ -111,10 +103,11 @@ class RabbitAnnotationDrivenConfiguration { @ConditionalOnMissingBean(name = "rabbitListenerContainerFactory") @ConditionalOnProperty(prefix = "spring.rabbitmq.listener", name = "type", havingValue = "direct") DirectRabbitListenerContainerFactory directRabbitListenerContainerFactory( - DirectRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory) { + DirectRabbitListenerContainerFactoryConfigurer configurer, ConnectionFactory connectionFactory, + ObjectProvider> directContainerCustomizer) { DirectRabbitListenerContainerFactory factory = new DirectRabbitListenerContainerFactory(); configurer.configure(factory, connectionFactory); - this.directContainerCustomizer.ifUnique(factory::setContainerCustomizer); + directContainerCustomizer.ifUnique(factory::setContainerCustomizer); return factory; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java index 31a523435cf..db625a906a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/amqp/RabbitAutoConfigurationTests.java @@ -64,6 +64,7 @@ import org.springframework.boot.test.system.CapturedOutput; import org.springframework.boot.test.system.OutputCaptureExtension; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @@ -78,6 +79,7 @@ import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -854,17 +856,20 @@ class RabbitAutoConfigurationTests { } @Test - void simpleContainerCustomizer() { - this.contextRunner.withUserConfiguration(SimpleContainerCustomizerConfiguration.class).run( - (context) -> assertThat(context.getBean(SimpleContainerCustomizerConfiguration.class).customizerCalled) - .isTrue()); + @SuppressWarnings("unchecked") + void whenASimpleContainerCustomizerIsDefinedThenItIsCalledToConfigureTheContainer() { + this.contextRunner.withUserConfiguration(SimpleContainerCustomizerConfiguration.class) + .run((context) -> verify(context.getBean(ContainerCustomizer.class)) + .configure(any(SimpleMessageListenerContainer.class))); } @Test - void directContainerCustomizer() { + @SuppressWarnings("unchecked") + void whenADirectContainerCustomizerIsDefinedThenItIsCalledToConfigureTheContainer() { this.contextRunner.withUserConfiguration(DirectContainerCustomizerConfiguration.class) - .withPropertyValues("spring.rabbitmq.listener.type:direct").run((context) -> assertThat( - context.getBean(DirectContainerCustomizerConfiguration.class).customizerCalled).isTrue()); + .withPropertyValues("spring.rabbitmq.listener.type:direct") + .run((context) -> verify(context.getBean(ContainerCustomizer.class)) + .configure(any(DirectMessageListenerContainer.class))); } private com.rabbitmq.client.ConnectionFactory getTargetConnectionFactory(AssertableApplicationContext context) { @@ -1131,36 +1136,36 @@ class RabbitAutoConfigurationTests { } + @Import(TestListener.class) @Configuration(proxyBeanMethods = false) static class SimpleContainerCustomizerConfiguration { - boolean customizerCalled; - - @RabbitListener(queues = "test", autoStartup = "false") - void listen(String in) { - } - @Bean + @SuppressWarnings("unchecked") ContainerCustomizer customizer() { - return (container) -> this.customizerCalled = true; + return mock(ContainerCustomizer.class); } } + @Import(TestListener.class) @Configuration(proxyBeanMethods = false) static class DirectContainerCustomizerConfiguration { - boolean customizerCalled; + @Bean + @SuppressWarnings("unchecked") + ContainerCustomizer customizer() { + return mock(ContainerCustomizer.class); + } + + } + + static class TestListener { @RabbitListener(queues = "test", autoStartup = "false") void listen(String in) { } - @Bean - ContainerCustomizer customizer() { - return (container) -> this.customizerCalled = true; - } - } }