Skip to content

Commit 5fccf26

Browse files
artembilangaryrussell
authored andcommitted
GH-914: Honor AllowBeanDefOverriding = false (#915)
* GH-914: Honor AllowBeanDefOverriding = false Fixes #914 * Rework `RabbitBootstrapConfiguration` into the `ImportBeanDefinitionRegistrar` and check for bean definitions presence it is going to register. This way an override from the `RabbitListenerTestBootstrap` is going to have a precedence and its `RabbitListenerTestHarness` won't allow a regular `RabbitListenerAnnotationBeanPostProcessor` to be registered * Rework `TestRabbitTemplate` to gather all the listener container from the `ContextRefreshedEvent` instead of the `SmartInitializingSingleton`. Looks like Spring doesn't care about their order, therefore we need to be sure that `RabbitListenerAnnotationBeanPostProcessor` has populated its `registry` with containers before. * Demonstrate that `allowBeanDefinitionOverriding = false` works well now in the `ExampleRabbitListenerCaptureTest` * Optimize `checkTestConfigs` and `updateCopyrights` Gradle tasks for their `inputs` and `outputs` for better `UP-TO-DATE` handling **Cherry-pick to 2.1.x without `build.gradle` changes** * * Fix typo in the `ExampleRabbitListenerCaptureTest`
1 parent 7df4a0d commit 5fccf26

File tree

4 files changed

+76
-50
lines changed

4 files changed

+76
-50
lines changed

spring-rabbit-test/src/main/java/org/springframework/amqp/rabbit/test/TestRabbitTemplate.java

+25-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2017-2018 the original author or authors.
2+
* Copyright 2017-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,11 +23,13 @@
2323
import static org.mockito.Mockito.mock;
2424

2525
import java.util.ArrayList;
26+
import java.util.Arrays;
2627
import java.util.HashMap;
2728
import java.util.Iterator;
2829
import java.util.List;
2930
import java.util.Map;
3031
import java.util.concurrent.atomic.AtomicReference;
32+
import java.util.stream.Stream;
3133

3234
import org.springframework.amqp.core.Message;
3335
import org.springframework.amqp.core.MessageBuilder;
@@ -41,10 +43,11 @@
4143
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
4244
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
4345
import org.springframework.beans.BeansException;
44-
import org.springframework.beans.factory.SmartInitializingSingleton;
4546
import org.springframework.beans.factory.annotation.Autowired;
4647
import org.springframework.context.ApplicationContext;
4748
import org.springframework.context.ApplicationContextAware;
49+
import org.springframework.context.ApplicationListener;
50+
import org.springframework.context.event.ContextRefreshedEvent;
4851

4952
import com.rabbitmq.client.AMQP.BasicProperties;
5053
import com.rabbitmq.client.Channel;
@@ -56,11 +59,13 @@
5659
* It does not currently support publisher confirms/returns.
5760
*
5861
* @author Gary Russell
62+
* @author Artem Bilan
5963
*
6064
* @since 2.0
6165
*
6266
*/
63-
public class TestRabbitTemplate extends RabbitTemplate implements ApplicationContextAware, SmartInitializingSingleton {
67+
public class TestRabbitTemplate extends RabbitTemplate
68+
implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
6469

6570
private static final String REPLY_QUEUE = "testRabbitTemplateReplyTo";
6671

@@ -82,22 +87,21 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
8287
}
8388

8489
@Override
85-
public void afterSingletonsInstantiated() {
86-
this.registry.getListenerContainers()
87-
.stream()
88-
.map(container -> (AbstractMessageListenerContainer) container)
89-
.forEach(c -> {
90-
for (String queue : c.getQueueNames()) {
91-
setupListener(c, queue);
92-
}
93-
});
94-
this.applicationContext.getBeansOfType(AbstractMessageListenerContainer.class).values()
95-
.stream()
96-
.forEach(container -> {
97-
for (String queue : container.getQueueNames()) {
98-
setupListener(container, queue);
99-
}
100-
});
90+
public void onApplicationEvent(ContextRefreshedEvent event) {
91+
if (event.getApplicationContext().equals(this.applicationContext)) {
92+
Stream<AbstractMessageListenerContainer> registryListenerContainers =
93+
this.registry.getListenerContainers()
94+
.stream()
95+
.map(AbstractMessageListenerContainer.class::cast);
96+
97+
Stream<AbstractMessageListenerContainer> listenerContainerBeans =
98+
this.applicationContext.getBeansOfType(AbstractMessageListenerContainer.class).values().stream();
99+
100+
Stream.concat(registryListenerContainers, listenerContainerBeans)
101+
.forEach(container ->
102+
Arrays.stream(container.getQueueNames())
103+
.forEach(queue -> setupListener(container, queue)));
104+
}
101105
}
102106

103107
private void setupListener(AbstractMessageListenerContainer container, String queue) {
@@ -143,8 +147,8 @@ protected Message doSendAndReceiveWithFixed(String exchange, String routingKey,
143147
Envelope envelope = new Envelope(1, false, "", REPLY_QUEUE);
144148
reply.set(MessageBuilder.withBody(i.getArgument(4)) // NOSONAR magic #
145149
.andProperties(getMessagePropertiesConverter()
146-
.toMessageProperties(i.getArgument(3), envelope, // NOSONAR magic #
147-
adapter.getEncoding()))
150+
.toMessageProperties(i.getArgument(3), envelope, // NOSONAR magic #
151+
adapter.getEncoding()))
148152
.build());
149153
return null;
150154
}).given(channel).basicPublish(anyString(), anyString(), anyBoolean(), any(BasicProperties.class),

spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/ExampleRabbitListenerCaptureTest.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016 the original author or authors.
2+
* Copyright 2016-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,21 +39,25 @@
3939
import org.springframework.amqp.rabbit.junit.BrokerRunning;
4040
import org.springframework.amqp.rabbit.test.RabbitListenerTestHarness.InvocationData;
4141
import org.springframework.beans.factory.annotation.Autowired;
42+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
4243
import org.springframework.context.annotation.Bean;
4344
import org.springframework.context.annotation.Configuration;
4445
import org.springframework.messaging.handler.annotation.Header;
4546
import org.springframework.messaging.handler.annotation.Payload;
4647
import org.springframework.test.annotation.DirtiesContext;
4748
import org.springframework.test.context.ContextConfiguration;
48-
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
49+
import org.springframework.test.context.junit4.SpringRunner;
50+
import org.springframework.test.context.support.AnnotationConfigContextLoader;
4951

5052
/**
5153
* @author Gary Russell
54+
* @author Artem Bilan
55+
*
5256
* @since 1.6
5357
*
5458
*/
55-
@ContextConfiguration
56-
@RunWith(SpringJUnit4ClassRunner.class)
59+
@ContextConfiguration(loader = ExampleRabbitListenerCaptureTest.NoBeansOverrideAnnotationConfigContextLoader.class)
60+
@RunWith(SpringRunner.class)
5761
@DirtiesContext
5862
public class ExampleRabbitListenerCaptureTest {
5963

@@ -179,4 +183,15 @@ public void foo(@Payload String foo, @Header("amqp_receivedRoutingKey") String r
179183

180184
}
181185

186+
187+
public static class NoBeansOverrideAnnotationConfigContextLoader extends AnnotationConfigContextLoader {
188+
189+
@Override
190+
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
191+
beanFactory.setAllowBeanDefinitionOverriding(false);
192+
}
193+
194+
}
195+
182196
}
197+

spring-rabbit-test/src/test/java/org/springframework/amqp/rabbit/test/TestRabbitTemplateTests.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import static org.mockito.BDDMockito.willReturn;
2424
import static org.mockito.Mockito.mock;
2525

26-
import java.io.IOException;
27-
2826
import org.junit.Test;
2927
import org.junit.runner.RunWith;
3028

@@ -45,6 +43,8 @@
4543

4644
/**
4745
* @author Gary Russell
46+
* @author Artem Bilan
47+
*
4848
* @since 2.0
4949
*
5050
*/
@@ -87,12 +87,12 @@ public static class Config {
8787
public String smlc1In = "smlc1:";
8888

8989
@Bean
90-
public TestRabbitTemplate template() throws IOException {
90+
public TestRabbitTemplate template() {
9191
return new TestRabbitTemplate(connectionFactory());
9292
}
9393

9494
@Bean
95-
public ConnectionFactory connectionFactory() throws IOException {
95+
public ConnectionFactory connectionFactory() {
9696
ConnectionFactory factory = mock(ConnectionFactory.class);
9797
Connection connection = mock(Connection.class);
9898
Channel channel = mock(Channel.class);
@@ -103,7 +103,7 @@ public ConnectionFactory connectionFactory() throws IOException {
103103
}
104104

105105
@Bean
106-
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() throws IOException {
106+
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
107107
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
108108
factory.setConnectionFactory(connectionFactory());
109109
return factory;
@@ -125,7 +125,7 @@ public String baz(String in) {
125125
}
126126

127127
@Bean
128-
public SimpleMessageListenerContainer smlc1() throws IOException {
128+
public SimpleMessageListenerContainer smlc1() {
129129
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
130130
container.setQueueNames("foo", "bar");
131131
container.setMessageListener(new MessageListenerAdapter(new Object() {
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,37 +18,44 @@
1818

1919
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
2020
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistry;
21-
import org.springframework.beans.factory.config.BeanDefinition;
22-
import org.springframework.context.annotation.Bean;
23-
import org.springframework.context.annotation.Configuration;
24-
import org.springframework.context.annotation.Role;
21+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
22+
import org.springframework.beans.factory.support.RootBeanDefinition;
23+
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
24+
import org.springframework.core.type.AnnotationMetadata;
2525

2626
/**
27-
* {@code @Configuration} class that registers a {@link RabbitListenerAnnotationBeanPostProcessor}
28-
* bean capable of processing Spring's @{@link RabbitListener} annotation. Also register
29-
* a default {@link RabbitListenerEndpointRegistry}.
27+
* An {@link ImportBeanDefinitionRegistrar} class that registers
28+
* a {@link RabbitListenerAnnotationBeanPostProcessor} bean capable of processing
29+
* Spring's @{@link RabbitListener} annotation.
30+
* Also register a default {@link RabbitListenerEndpointRegistry}.
3031
*
3132
* <p>This configuration class is automatically imported when using the @{@link EnableRabbit}
32-
* annotation. See {@link EnableRabbit} Javadoc for complete usage.
33+
* annotation.
3334
*
3435
* @author Stephane Nicoll
36+
* @author Artem Bilan
37+
*
3538
* @since 1.4
39+
*
3640
* @see RabbitListenerAnnotationBeanPostProcessor
3741
* @see RabbitListenerEndpointRegistry
3842
* @see EnableRabbit
3943
*/
40-
@Configuration
41-
public class RabbitBootstrapConfiguration {
44+
public class RabbitBootstrapConfiguration implements ImportBeanDefinitionRegistrar {
4245

43-
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
44-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
45-
public RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
46-
return new RabbitListenerAnnotationBeanPostProcessor();
47-
}
46+
@Override
47+
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
48+
if (!registry.containsBeanDefinition(
49+
RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)) {
50+
51+
registry.registerBeanDefinition(RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME,
52+
new RootBeanDefinition(RabbitListenerAnnotationBeanPostProcessor.class));
53+
}
4854

49-
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)
50-
public RabbitListenerEndpointRegistry defaultRabbitListenerEndpointRegistry() {
51-
return new RabbitListenerEndpointRegistry();
55+
if (!registry.containsBeanDefinition(RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME)) {
56+
registry.registerBeanDefinition(RabbitListenerConfigUtils.RABBIT_LISTENER_ENDPOINT_REGISTRY_BEAN_NAME,
57+
new RootBeanDefinition(RabbitListenerEndpointRegistry.class));
58+
}
5259
}
5360

5461
}

0 commit comments

Comments
 (0)