diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.java index 82399ae4ac..98504dbfad 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.java @@ -18,10 +18,13 @@ package org.springframework.integration.http.inbound; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicBoolean; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; import org.springframework.web.HttpRequestHandler; @@ -37,21 +40,21 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl * detects and registers {@link RequestMappingInfo}s for {@link HttpRequestHandlingEndpointSupport} * from a Spring Integration HTTP configuration of * {@code } and {@code } elements. - *

- * This class is automatically configured as bean in the application context on the parsing phase of + *

+ * This class is automatically configured as a bean in the application context during the parsing phase of * the {@code } and {@code } elements, if there is none registered, yet. * However it can be configured as a regular bean with appropriate configuration for * {@link RequestMappingHandlerMapping}. It is recommended to have only one similar bean in the application context * using the 'id' {@link org.springframework.integration.http.support.HttpContextUtils#HANDLER_MAPPING_BEAN_NAME}. - *

- * In most cases Spring MVC offers to configure Request Mapping via {@link org.springframework.stereotype.Controller} + *

+ * In most cases, Spring MVC offers to configure Request Mapping via {@code org.springframework.stereotype.Controller} * and {@link org.springframework.web.bind.annotation.RequestMapping}. * That's why Spring MVC's Handler Mapping infrastructure relies on {@link org.springframework.web.method.HandlerMethod}, - * as different methods at the same {@link org.springframework.stereotype.Controller} user-class may have their own + * as different methods at the same {@code org.springframework.stereotype.Controller} user-class may have their own * {@link org.springframework.web.bind.annotation.RequestMapping}. On the other side, all Spring Integration HTTP Inbound * Endpoints are configured on the basis of the same {@link HttpRequestHandlingEndpointSupport} class and there is no * single {@link RequestMappingInfo} configuration without {@link org.springframework.web.method.HandlerMethod} in Spring MVC. - * Accordingly {@link IntegrationRequestMappingHandlerMapping} is a some {@link org.springframework.web.servlet.HandlerMapping} + * Accordingly {@link IntegrationRequestMappingHandlerMapping} is a {@link org.springframework.web.servlet.HandlerMapping} * compromise implementation between method-level annotations and component-level (e.g. Spring Integration XML) configurations. * * @author Artem Bilan @@ -60,7 +63,8 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl * * @since 3.0 */ -public final class IntegrationRequestMappingHandlerMapping extends RequestMappingHandlerMapping { +public final class IntegrationRequestMappingHandlerMapping extends RequestMappingHandlerMapping + implements ApplicationListener { private static final Method HANDLE_REQUEST_METHOD = ReflectionUtils.findMethod(HttpRequestHandler.class, "handleRequest", HttpServletRequest.class, HttpServletResponse.class); @@ -77,6 +81,8 @@ public final class IntegrationRequestMappingHandlerMapping extends RequestMappin ReflectionUtils.makeAccessible(CREATE_REQUEST_MAPPING_INFO_METHOD); } + private final AtomicBoolean initialized = new AtomicBoolean(); + @Override protected final boolean isHandler(Class beanType) { return HttpRequestHandlingEndpointSupport.class.isAssignableFrom(beanType); @@ -156,4 +162,23 @@ public final class IntegrationRequestMappingHandlerMapping extends RequestMappin return (RequestMappingInfo) ReflectionUtils.invokeMethod(CREATE_REQUEST_MAPPING_INFO_METHOD, this, createRequestMappingInfoParams); } + @Override + public void afterPropertiesSet() { + // No-op in favor of onApplicationEvent + } + + /** + * {@link HttpRequestHandlingEndpointSupport}s may depend on auto-created + * {@code requestChannel}s, so MVC Handlers detection should be postponed + * as late as possible. + * + * @see RequestMappingHandlerMapping#afterPropertiesSet() + */ + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if (!this.initialized.getAndSet(true)) { + super.afterPropertiesSet(); + } + } + }