diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java index 0e1e1d2f7e3..ef2e55079d6 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/DispatcherHandler.java @@ -36,6 +36,7 @@ import org.springframework.web.server.ResponseStatusException; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebHandler; import org.springframework.web.server.adapter.HttpWebHandlerAdapter; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; /** * Central dispatcher for HTTP request handlers/controllers. Dispatches to registered @@ -170,7 +171,14 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware { * Expose a dispatcher-based {@link HttpHandler} for the given application context, * typically for direct registration with an engine adapter such as * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter}. - * @param applicationContext the application context to find the handler beans in + * + *

Delegates to {@link WebHttpHandlerBuilder#applicationContext} that + * detects the target {@link DispatcherHandler} along with + * {@link org.springframework.web.server.WebFilter}s, and + * {@link org.springframework.web.server.WebExceptionHandler}s in the given + * ApplicationContext. + * + * @param context the application context to find the handler beans in * @see #DispatcherHandler(ApplicationContext) * @see HttpWebHandlerAdapter * @see org.springframework.http.server.reactive.ServletHttpHandlerAdapter @@ -178,8 +186,8 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware { * @see org.springframework.http.server.reactive.RxNettyHttpHandlerAdapter * @see org.springframework.http.server.reactive.UndertowHttpHandlerAdapter */ - public static HttpHandler toHttpHandler(ApplicationContext applicationContext) { - return new HttpWebHandlerAdapter(new DispatcherHandler(applicationContext)); + public static HttpHandler toHttpHandler(ApplicationContext context) { + return WebHttpHandlerBuilder.applicationContext(context).build(); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java index 28e72758959..342109f7fdc 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java @@ -61,6 +61,7 @@ import org.springframework.validation.Validator; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.accept.CompositeContentTypeResolver; import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder; @@ -74,6 +75,8 @@ import org.springframework.web.reactive.result.method.annotation.ResponseEntityR import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebExceptionHandler; +import org.springframework.web.server.handler.ResponseStatusExceptionHandler; /** * The main class for Spring Web Reactive configuration. @@ -116,6 +119,16 @@ public class WebReactiveConfigurationSupport implements ApplicationContextAware } + @Bean + public DispatcherHandler webHandler() { + return new DispatcherHandler(); + } + + @Bean + public WebExceptionHandler responseStatusExceptionHandler() { + return new ResponseStatusExceptionHandler(); + } + @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java index e6f373a9de2..9ee0e3ab56f 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java @@ -29,9 +29,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.web.client.RestTemplate; -import org.springframework.web.reactive.DispatcherHandler; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; -import org.springframework.web.server.handler.ResponseStatusExceptionHandler; import static org.springframework.http.RequestEntity.get; import static org.springframework.http.RequestEntity.options; @@ -53,10 +51,7 @@ public abstract class AbstractRequestMappingIntegrationTests extends AbstractHtt protected HttpHandler createHttpHandler() { this.restTemplate = initRestTemplate(); this.applicationContext = initApplicationContext(); - return WebHttpHandlerBuilder - .webHandler(new DispatcherHandler(this.applicationContext)) - .exceptionHandlers(new ResponseStatusExceptionHandler()) - .build(); + return WebHttpHandlerBuilder.applicationContext(this.applicationContext).build(); } protected abstract ApplicationContext initApplicationContext(); diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java b/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java index 70bf4305192..6be91d79f15 100644 --- a/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java +++ b/spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java @@ -17,8 +17,13 @@ package org.springframework.web.server.adapter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.http.server.reactive.HttpHandler; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -28,6 +33,7 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebHandler; import org.springframework.web.server.handler.ExceptionHandlingWebHandler; import org.springframework.web.server.handler.FilteringWebHandler; +import org.springframework.web.server.session.DefaultWebSessionManager; import org.springframework.web.server.session.WebSessionManager; /** @@ -52,6 +58,13 @@ import org.springframework.web.server.session.WebSessionManager; */ public class WebHttpHandlerBuilder { + /** Well-known name for the target WebHandler in the bean factory. */ + public static final String WEB_HANDLER_BEAN_NAME = "webHandler"; + + /** Well-known name for the WebSessionManager in the bean factory. */ + public static final String WEB_SESSION_MANAGER_BEAN_NAME = "webSessionManager"; + + private final WebHandler targetHandler; private final List filters = new ArrayList<>(); @@ -74,11 +87,66 @@ public class WebHttpHandlerBuilder { /** * Factory method to create a new builder instance. * @param webHandler the target handler for the request + * @return the prepared builder */ public static WebHttpHandlerBuilder webHandler(WebHandler webHandler) { return new WebHttpHandlerBuilder(webHandler); } + /** + * Factory method to create a new builder instance by detecting beans in an + * {@link ApplicationContext}. The following are detected: + *

+ * @param context the application context to use for the lookup + * @return the prepared builder + */ + public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) { + + // Target WebHandler + + WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder( + context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class)); + + // WebFilter... + + Collection filters = BeanFactoryUtils.beansOfTypeIncludingAncestors( + context, WebFilter.class, true, false).values(); + + WebFilter[] sortedFilters = filters.toArray(new WebFilter[filters.size()]); + AnnotationAwareOrderComparator.sort(sortedFilters); + builder.filters(sortedFilters); + + // WebExceptionHandler... + + Collection handlers = BeanFactoryUtils.beansOfTypeIncludingAncestors( + context, WebExceptionHandler.class, true, false).values(); + + WebExceptionHandler[] sortedHandlers = handlers.toArray(new WebExceptionHandler[handlers.size()]); + AnnotationAwareOrderComparator.sort(sortedHandlers); + builder.exceptionHandlers(sortedHandlers); + + // WebSessionManager + + try { + builder.sessionManager( + context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class)); + } + catch (NoSuchBeanDefinitionException ex) { + // Fall back on default + } + + return builder; + } + /** * Add the given filters to use for processing requests. @@ -104,8 +172,8 @@ public class WebHttpHandlerBuilder { /** * Configure the {@link WebSessionManager} to set on the - * {@link ServerWebExchange WebServerExchange} - * created for each HTTP request. + * {@link ServerWebExchange WebServerExchange}. + *

By default {@link DefaultWebSessionManager} is used. * @param sessionManager the session manager * @see HttpWebHandlerAdapter#setSessionManager(WebSessionManager) */