Skip to content

Commit 24e8048

Browse files
artembilangaryrussell
authored andcommitted
GH-973: Higher order for RabbitListTestBootstrap (#976)
* GH-973: Higher order for RabbitListTestBootstrap Fixes #973 When we use `@EnableRabbit` and `@RabbitListenerTest` in the same configuration set, e.g. mixing real `@Configuration` and test one for `@RabbitListenerTest`, we may end up with the case when `@EnableRabbit` is processed before `@RabbitListenerTest`, so, `RabbitListenerTestHarness` bean is not going to appear in the application context. * Implement a `DeferredImportSelector` with an `@Order` for the `@EnableRabbit` as well as `RabbitListenerTest` giving higher order to the `RabbitListenerTestSelector`, so `RabbitListenerTestBootstrap` is processed and register its `RabbitListenerTestHarness` earlier, than it is done by the `RabbitBootstrapConfiguration` **Cherry-pick to 2.1.x** * * Fix Checkstyle * Add JavaDocs to new classes
1 parent ecb5e11 commit 24e8048

File tree

6 files changed

+105
-26
lines changed

6 files changed

+105
-26
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,16 @@
3030
* {@code @RabbitListener} beans to capture arguments and result (if any).
3131
*
3232
* @author Gary Russell
33+
* @author Artem Bilan
34+
*
3335
* @since 1.6
3436
*
3537
*/
3638
@Target(ElementType.TYPE)
3739
@Retention(RetentionPolicy.RUNTIME)
3840
@Documented
3941
@EnableRabbit
40-
@Import(RabbitListenerTestBootstrap.class)
42+
@Import(RabbitListenerTestSelector.class)
4143
public @interface RabbitListenerTest {
4244

4345
/**

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,31 @@
1616

1717
package org.springframework.amqp.rabbit.test;
1818

19-
import org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor;
2019
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
21-
import org.springframework.beans.factory.config.BeanDefinition;
22-
import org.springframework.context.annotation.Bean;
20+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
21+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2322
import org.springframework.context.annotation.Configuration;
24-
import org.springframework.context.annotation.ImportAware;
25-
import org.springframework.context.annotation.Role;
23+
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
2624
import org.springframework.core.type.AnnotationMetadata;
2725

2826
/**
2927
* Overrides the default BPP with a {@link RabbitListenerTestHarness}.
3028
*
3129
* @author Gary Russell
30+
* @author Artem Bilan
31+
*
3232
* @since 1.6
3333
*
3434
*/
3535
@Configuration
36-
public class RabbitListenerTestBootstrap implements ImportAware {
37-
38-
private AnnotationMetadata importMetadata;
36+
public class RabbitListenerTestBootstrap implements ImportBeanDefinitionRegistrar {
3937

4038
@Override
41-
public void setImportMetadata(AnnotationMetadata importMetadata) {
42-
this.importMetadata = importMetadata;
43-
}
44-
45-
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
46-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
47-
public RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
48-
return new RabbitListenerTestHarness(this.importMetadata);
39+
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
40+
registry.registerBeanDefinition(RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME,
41+
BeanDefinitionBuilder.rootBeanDefinition(RabbitListenerTestHarness.class)
42+
.addConstructorArgValue(importingClassMetadata)
43+
.getBeanDefinition());
4944
}
5045

5146
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,6 @@ public <T> T getSpy(String id) {
114114
return (T) this.listeners.get(id);
115115
}
116116

117-
@Override
118-
public int getOrder() {
119-
return super.getOrder() - 100;
120-
}
121-
122117
private static final class CaptureAdvice implements MethodInterceptor {
123118

124119
private final BlockingQueue<InvocationData> invocationData = new LinkedBlockingQueue<>();
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.amqp.rabbit.test;
18+
19+
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurationSelector;
20+
import org.springframework.core.Ordered;
21+
import org.springframework.core.annotation.Order;
22+
import org.springframework.core.type.AnnotationMetadata;
23+
24+
/**
25+
* A {@link RabbitListenerConfigurationSelector} extension to register
26+
* a {@link RabbitListenerTestBootstrap}, but already with the higher order,
27+
* so the {@link RabbitListenerTestHarness} bean is registered earlier,
28+
* than {@link org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor}.
29+
*
30+
* @author Artem Bilan
31+
*
32+
* @since 2.1.6
33+
*/
34+
@Order(Ordered.LOWEST_PRECEDENCE - 100)
35+
public class RabbitListenerTestSelector extends RabbitListenerConfigurationSelector {
36+
37+
@Override
38+
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
39+
return new String[] { RabbitListenerTestBootstrap.class.getName() };
40+
}
41+
42+
}

spring-rabbit/src/main/java/org/springframework/amqp/rabbit/annotation/EnableRabbit.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
*
4848
* The {@code RabbitListenerContainerFactory} is responsible to create the listener container
4949
* responsible for a particular endpoint. Typical implementations, as the
50-
* {@link org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory SimpleRabbitListenerContainerFactory}
50+
* {@link org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
51+
* SimpleRabbitListenerContainerFactory}
5152
* used in the sample above, provides the necessary configuration options that are supported by
5253
* the underlying {@link org.springframework.amqp.rabbit.listener.MessageListenerContainer MessageListenerContainer}.
5354
*
@@ -111,9 +112,11 @@
111112
* // process incoming message
112113
* }</pre>
113114
*
114-
* These features are abstracted by the {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
115+
* These features are abstracted by the
116+
* {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
115117
* MessageHandlerMethodFactory} that is responsible to build the necessary invoker to process
116-
* the annotated method. By default, {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
118+
* the annotated method. By default,
119+
* {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
117120
* DefaultMessageHandlerMethodFactory} is used.
118121
*
119122
* <p>When more control is desired, a {@code @Configuration} class may implement
@@ -249,7 +252,10 @@
249252
* definition registered in the context in case you use the XML configuration.
250253
*
251254
* @author Stephane Nicoll
255+
* @author Artem Bilan
256+
*
252257
* @since 1.4
258+
*
253259
* @see RabbitListener
254260
* @see RabbitListenerAnnotationBeanPostProcessor
255261
* @see org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar
@@ -258,6 +264,6 @@
258264
@Target(ElementType.TYPE)
259265
@Retention(RetentionPolicy.RUNTIME)
260266
@Documented
261-
@Import(RabbitBootstrapConfiguration.class)
267+
@Import(RabbitListenerConfigurationSelector.class)
262268
public @interface EnableRabbit {
263269
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.amqp.rabbit.annotation;
18+
19+
import org.springframework.context.annotation.DeferredImportSelector;
20+
import org.springframework.core.annotation.Order;
21+
import org.springframework.core.type.AnnotationMetadata;
22+
23+
/**
24+
* A {@link DeferredImportSelector} implementation with the lowest order to import a
25+
* {@link RabbitBootstrapConfiguration} as late as possible.
26+
*
27+
* @author Artem Bilan
28+
*
29+
* @since 2.1.6
30+
*/
31+
@Order
32+
public class RabbitListenerConfigurationSelector implements DeferredImportSelector {
33+
34+
@Override
35+
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
36+
return new String[] { RabbitBootstrapConfiguration.class.getName() };
37+
}
38+
39+
}

0 commit comments

Comments
 (0)