Skip to content

Commit

Permalink
GH-973: Higher order for RabbitListTestBootstrap (#976)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
artembilan authored and garyrussell committed Apr 10, 2019
1 parent 1333fda commit c71ed1e
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@
* {@code @RabbitListener} beans to capture arguments and result (if any).
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 1.6
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EnableRabbit
@Import(RabbitListenerTestBootstrap.class)
@Import(RabbitListenerTestSelector.class)
public @interface RabbitListenerTest {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,31 @@

package org.springframework.amqp.rabbit.test;

import org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor;
import org.springframework.amqp.rabbit.config.RabbitListenerConfigUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

/**
* Overrides the default BPP with a {@link RabbitListenerTestHarness}.
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 1.6
*
*/
@Configuration
public class RabbitListenerTestBootstrap implements ImportAware {

private AnnotationMetadata importMetadata;
public class RabbitListenerTestBootstrap implements ImportBeanDefinitionRegistrar {

@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.importMetadata = importMetadata;
}

@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
return new RabbitListenerTestHarness(this.importMetadata);
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
registry.registerBeanDefinition(RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME,
BeanDefinitionBuilder.rootBeanDefinition(RabbitListenerTestHarness.class)
.addConstructorArgValue(importingClassMetadata)
.getBeanDefinition());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,6 @@ public <T> T getSpy(String id) {
return (T) this.listeners.get(id);
}

@Override
public int getOrder() {
return super.getOrder() - 100;
}

private static final class CaptureAdvice implements MethodInterceptor {

private final BlockingQueue<InvocationData> invocationData = new LinkedBlockingQueue<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.amqp.rabbit.test;

import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurationSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;

/**
* A {@link RabbitListenerConfigurationSelector} extension to register
* a {@link RabbitListenerTestBootstrap}, but already with the higher order,
* so the {@link RabbitListenerTestHarness} bean is registered earlier,
* than {@link org.springframework.amqp.rabbit.annotation.RabbitListenerAnnotationBeanPostProcessor}.
*
* @author Artem Bilan
*
* @since 2.1.6
*/
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class RabbitListenerTestSelector extends RabbitListenerConfigurationSelector {

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { RabbitListenerTestBootstrap.class.getName() };
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
*
* The {@code RabbitListenerContainerFactory} is responsible to create the listener container
* responsible for a particular endpoint. Typical implementations, as the
* {@link org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory SimpleRabbitListenerContainerFactory}
* {@link org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory
* SimpleRabbitListenerContainerFactory}
* used in the sample above, provides the necessary configuration options that are supported by
* the underlying {@link org.springframework.amqp.rabbit.listener.MessageListenerContainer MessageListenerContainer}.
*
Expand Down Expand Up @@ -111,9 +112,11 @@
* // process incoming message
* }</pre>
*
* These features are abstracted by the {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
* These features are abstracted by the
* {@link org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory
* MessageHandlerMethodFactory} that is responsible to build the necessary invoker to process
* the annotated method. By default, {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
* the annotated method. By default,
* {@link org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory
* DefaultMessageHandlerMethodFactory} is used.
*
* <p>When more control is desired, a {@code @Configuration} class may implement
Expand Down Expand Up @@ -249,7 +252,10 @@
* definition registered in the context in case you use the XML configuration.
*
* @author Stephane Nicoll
* @author Artem Bilan
*
* @since 1.4
*
* @see RabbitListener
* @see RabbitListenerAnnotationBeanPostProcessor
* @see org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar
Expand All @@ -258,6 +264,6 @@
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(RabbitBootstrapConfiguration.class)
@Import(RabbitListenerConfigurationSelector.class)
public @interface EnableRabbit {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.amqp.rabbit.annotation;

import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;

/**
* A {@link DeferredImportSelector} implementation with the lowest order to import a
* {@link RabbitBootstrapConfiguration} as late as possible.
*
* @author Artem Bilan
*
* @since 2.1.6
*/
@Order
public class RabbitListenerConfigurationSelector implements DeferredImportSelector {

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] { RabbitBootstrapConfiguration.class.getName() };
}

}

0 comments on commit c71ed1e

Please sign in to comment.