Reactive setup refinements
This commit is contained in:
parent
578af59f0c
commit
89717e1783
|
|
@ -54,6 +54,7 @@ import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
|
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
|
||||||
|
|
@ -159,6 +160,7 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware {
|
||||||
* a {@link org.springframework.web.server.adapter.WebHttpHandlerBuilder}.
|
* a {@link org.springframework.web.server.adapter.WebHttpHandlerBuilder}.
|
||||||
* @param applicationContext the application context to find the handler beans in
|
* @param applicationContext the application context to find the handler beans in
|
||||||
* @see #DispatcherHandler(ApplicationContext)
|
* @see #DispatcherHandler(ApplicationContext)
|
||||||
|
* @see org.springframework.web.server.adapter.WebHttpHandlerBuilder#webHandler
|
||||||
*/
|
*/
|
||||||
public static WebHandler toWebHandler(ApplicationContext applicationContext) {
|
public static WebHandler toWebHandler(ApplicationContext applicationContext) {
|
||||||
return new DispatcherHandler(applicationContext);
|
return new DispatcherHandler(applicationContext);
|
||||||
|
|
@ -167,10 +169,14 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware {
|
||||||
/**
|
/**
|
||||||
* Expose a dispatcher-based {@link HttpHandler} for the given application context,
|
* Expose a dispatcher-based {@link HttpHandler} for the given application context,
|
||||||
* typically for direct registration with an engine adapter such as
|
* typically for direct registration with an engine adapter such as
|
||||||
* {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter}.
|
* {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter}.
|
||||||
* @param applicationContext the application context to find the handler beans in
|
* @param applicationContext the application context to find the handler beans in
|
||||||
* @see #DispatcherHandler(ApplicationContext)
|
* @see #DispatcherHandler(ApplicationContext)
|
||||||
* @see HttpWebHandlerAdapter
|
* @see HttpWebHandlerAdapter
|
||||||
|
* @see org.springframework.http.server.reactive.ServletHttpHandlerAdapter
|
||||||
|
* @see org.springframework.http.server.reactive.ReactorHttpHandlerAdapter
|
||||||
|
* @see org.springframework.http.server.reactive.RxNettyHttpHandlerAdapter
|
||||||
|
* @see org.springframework.http.server.reactive.UndertowHttpHandlerAdapter
|
||||||
*/
|
*/
|
||||||
public static HttpHandler toHttpHandler(ApplicationContext applicationContext) {
|
public static HttpHandler toHttpHandler(ApplicationContext applicationContext) {
|
||||||
return new HttpWebHandlerAdapter(new DispatcherHandler(applicationContext));
|
return new HttpWebHandlerAdapter(new DispatcherHandler(applicationContext));
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,14 @@ class DefaultRequest implements Request {
|
||||||
|
|
||||||
private final StrategiesSupplier strategies;
|
private final StrategiesSupplier strategies;
|
||||||
|
|
||||||
|
|
||||||
DefaultRequest(ServerWebExchange exchange, StrategiesSupplier strategies) {
|
DefaultRequest(ServerWebExchange exchange, StrategiesSupplier strategies) {
|
||||||
this.exchange = exchange;
|
this.exchange = exchange;
|
||||||
this.strategies = strategies;
|
this.strategies = strategies;
|
||||||
this.headers = new DefaultHeaders();
|
this.headers = new DefaultHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpMethod method() {
|
public HttpMethod method() {
|
||||||
return request().getMethod();
|
return request().getMethod();
|
||||||
|
|
@ -96,10 +98,8 @@ class DefaultRequest implements Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class DefaultHeaders implements Headers {
|
private class DefaultHeaders implements Headers {
|
||||||
|
|
||||||
|
|
||||||
private HttpHeaders delegate() {
|
private HttpHeaders delegate() {
|
||||||
return request().getHeaders();
|
return request().getHeaders();
|
||||||
}
|
}
|
||||||
|
|
@ -116,7 +116,8 @@ class DefaultRequest implements Request {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OptionalLong contentLength() {
|
public OptionalLong contentLength() {
|
||||||
return toOptionalLong(delegate().getContentLength());
|
long value = delegate().getContentLength();
|
||||||
|
return (value != -1 ? OptionalLong.of(value) : OptionalLong.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -137,18 +138,13 @@ class DefaultRequest implements Request {
|
||||||
@Override
|
@Override
|
||||||
public List<String> header(String headerName) {
|
public List<String> header(String headerName) {
|
||||||
List<String> headerValues = delegate().get(headerName);
|
List<String> headerValues = delegate().get(headerName);
|
||||||
return headerValues != null ? headerValues : Collections.emptyList();
|
return (headerValues != null ? headerValues : Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpHeaders asHttpHeaders() {
|
public HttpHeaders asHttpHeaders() {
|
||||||
return HttpHeaders.readOnlyHttpHeaders(delegate());
|
return HttpHeaders.readOnlyHttpHeaders(delegate());
|
||||||
}
|
}
|
||||||
|
|
||||||
private OptionalLong toOptionalLong(long value) {
|
|
||||||
return value != -1 ? OptionalLong.of(value) : OptionalLong.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,12 +44,9 @@ import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public abstract class RouterFunctions {
|
public abstract class RouterFunctions {
|
||||||
|
|
||||||
private static final HandlerFunction<Void> NOT_FOUND_HANDLER = request -> Response.notFound().build();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the {@link ServerWebExchange} attribute that contains the {@link Request}.
|
* Name of the {@link ServerWebExchange} attribute that contains the {@link Request}.
|
||||||
*/
|
*/
|
||||||
|
|
@ -59,15 +56,19 @@ public abstract class RouterFunctions {
|
||||||
* Name of the {@link ServerWebExchange} attribute that contains the URI
|
* Name of the {@link ServerWebExchange} attribute that contains the URI
|
||||||
* templates map, mapping variable names to values.
|
* templates map, mapping variable names to values.
|
||||||
*/
|
*/
|
||||||
public static final String URI_TEMPLATE_VARIABLES_ATTRIBUTE = RouterFunctions.class.getName() + ".uriTemplateVariables";
|
public static final String URI_TEMPLATE_VARIABLES_ATTRIBUTE =
|
||||||
|
RouterFunctions.class.getName() + ".uriTemplateVariables";
|
||||||
|
|
||||||
|
private static final HandlerFunction<Void> NOT_FOUND_HANDLER = request -> Response.notFound().build();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route to the given handler function if the given request predicate applies.
|
* Route to the given handler function if the given request predicate applies.
|
||||||
*
|
|
||||||
* @param predicate the predicate to test
|
* @param predicate the predicate to test
|
||||||
* @param handlerFunction the handler function to route to
|
* @param handlerFunction the handler function to route to
|
||||||
* @param <T> the type of the handler function
|
* @param <T> the type of the handler function
|
||||||
* @return a routing function that routes to {@code handlerFunction} if {@code predicate} evaluates to {@code true}
|
* @return a routing function that routes to {@code handlerFunction} if
|
||||||
|
* {@code predicate} evaluates to {@code true}
|
||||||
* @see RequestPredicates
|
* @see RequestPredicates
|
||||||
*/
|
*/
|
||||||
public static <T> RouterFunction<T> route(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
|
public static <T> RouterFunction<T> route(RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
|
||||||
|
|
@ -79,11 +80,11 @@ public abstract class RouterFunctions {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route to the given routing function if the given request predicate applies.
|
* Route to the given routing function if the given request predicate applies.
|
||||||
*
|
|
||||||
* @param predicate the predicate to test
|
* @param predicate the predicate to test
|
||||||
* @param routerFunction the routing function to route to
|
* @param routerFunction the routing function to route to
|
||||||
* @param <T> the type of the handler function
|
* @param <T> the type of the handler function
|
||||||
* @return a routing function that routes to {@code routerFunction} if {@code predicate} evaluates to {@code true}
|
* @return a routing function that routes to {@code routerFunction} if
|
||||||
|
* {@code predicate} evaluates to {@code true}
|
||||||
* @see RequestPredicates
|
* @see RequestPredicates
|
||||||
*/
|
*/
|
||||||
public static <T> RouterFunction<T> subroute(RequestPredicate predicate, RouterFunction<T> routerFunction) {
|
public static <T> RouterFunction<T> subroute(RequestPredicate predicate, RouterFunction<T> routerFunction) {
|
||||||
|
|
@ -102,9 +103,8 @@ public abstract class RouterFunctions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HttpHandler}.
|
* Convert the given {@linkplain RouterFunction routing function} into a {@link HttpHandler}.
|
||||||
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
||||||
*
|
|
||||||
* <p>The returned {@code HttpHandler} can be adapted to run in
|
* <p>The returned {@code HttpHandler} can be adapted to run in
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Servlet 3.1+ using the
|
* <li>Servlet 3.1+ using the
|
||||||
|
|
@ -116,18 +116,16 @@ public abstract class RouterFunctions {
|
||||||
* <li>Undertow using the
|
* <li>Undertow using the
|
||||||
* {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
|
* {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
|
||||||
* @param routerFunction the routing function to convert
|
* @param routerFunction the routing function to convert
|
||||||
* @return an http handler that handles HTTP request using the given routing function
|
* @return an http handler that handles HTTP request using the given routing function
|
||||||
*/
|
*/
|
||||||
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction) {
|
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction) {
|
||||||
return toHttpHandler(routerFunction, defaultStrategies());
|
return toHttpHandler(routerFunction, StrategiesSupplier.withDefaults());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HttpHandler},
|
* Convert the given {@linkplain RouterFunction routing function} into a {@link HttpHandler},
|
||||||
* using the given strategies.
|
* using the given strategies.
|
||||||
*
|
|
||||||
* <p>The returned {@code HttpHandler} can be adapted to run in
|
* <p>The returned {@code HttpHandler} can be adapted to run in
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Servlet 3.1+ using the
|
* <li>Servlet 3.1+ using the
|
||||||
|
|
@ -139,19 +137,17 @@ public abstract class RouterFunctions {
|
||||||
* <li>Undertow using the
|
* <li>Undertow using the
|
||||||
* {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
|
* {@link org.springframework.http.server.reactive.UndertowHttpHandlerAdapter}.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
|
||||||
* @param routerFunction the routing function to convert
|
* @param routerFunction the routing function to convert
|
||||||
* @param strategies the strategies to use
|
* @param strategies the strategies to use
|
||||||
* @return an http handler that handles HTTP request using the given routing function
|
* @return an http handler that handles HTTP request using the given routing function
|
||||||
*/
|
*/
|
||||||
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
||||||
Assert.notNull(routerFunction, "'routerFunction' must not be null");
|
Assert.notNull(routerFunction, "RouterFunction must not be null");
|
||||||
Assert.notNull(strategies, "'strategies' must not be null");
|
Assert.notNull(strategies, "StrategiesSupplier must not be null");
|
||||||
|
|
||||||
return new HttpWebHandlerAdapter(exchange -> {
|
return new HttpWebHandlerAdapter(exchange -> {
|
||||||
Request request = new DefaultRequest(exchange, strategies);
|
Request request = new DefaultRequest(exchange, strategies);
|
||||||
addAttributes(exchange, request);
|
addAttributes(exchange, request);
|
||||||
|
|
||||||
HandlerFunction<?> handlerFunction = routerFunction.route(request).orElse(notFound());
|
HandlerFunction<?> handlerFunction = routerFunction.route(request).orElse(notFound());
|
||||||
Response<?> response = handlerFunction.handle(request);
|
Response<?> response = handlerFunction.handle(request);
|
||||||
return response.writeTo(exchange, strategies);
|
return response.writeTo(exchange, strategies);
|
||||||
|
|
@ -159,28 +155,24 @@ public abstract class RouterFunctions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given {@code RouterFunction} into a {@code HandlerMapping}.
|
* Convert the given {@code RouterFunction} into a {@code HandlerMapping}.
|
||||||
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
||||||
*
|
|
||||||
* <p>The returned {@code HandlerMapping} can be run in a
|
* <p>The returned {@code HandlerMapping} can be run in a
|
||||||
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
||||||
*
|
|
||||||
* @param routerFunction the routing function to convert
|
* @param routerFunction the routing function to convert
|
||||||
* @return an handler mapping that maps HTTP request to a handler using the given routing function
|
* @return an handler mapping that maps HTTP request to a handler using the given routing function
|
||||||
* @see org.springframework.web.reactive.function.support.HandlerFunctionAdapter
|
* @see org.springframework.web.reactive.function.support.HandlerFunctionAdapter
|
||||||
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
||||||
*/
|
*/
|
||||||
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction) {
|
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction) {
|
||||||
return toHandlerMapping(routerFunction, defaultStrategies());
|
return toHandlerMapping(routerFunction, StrategiesSupplier.withDefaults());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HandlerMapping},
|
* Convert the given {@linkplain RouterFunction routing function} into a {@link HandlerMapping},
|
||||||
* using the given strategies.
|
* using the given strategies.
|
||||||
*
|
|
||||||
* <p>The returned {@code HandlerMapping} can be run in a
|
* <p>The returned {@code HandlerMapping} can be run in a
|
||||||
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
||||||
*
|
|
||||||
* @param routerFunction the routing function to convert
|
* @param routerFunction the routing function to convert
|
||||||
* @param strategies the strategies to use
|
* @param strategies the strategies to use
|
||||||
* @return an handler mapping that maps HTTP request to a handler using the given routing function
|
* @return an handler mapping that maps HTTP request to a handler using the given routing function
|
||||||
|
|
@ -188,21 +180,17 @@ public abstract class RouterFunctions {
|
||||||
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
||||||
*/
|
*/
|
||||||
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
||||||
Assert.notNull(routerFunction, "'routerFunction' must not be null");
|
Assert.notNull(routerFunction, "RouterFunction must not be null");
|
||||||
Assert.notNull(strategies, "'strategies' must not be null");
|
Assert.notNull(strategies, "StrategiesSupplier must not be null");
|
||||||
|
|
||||||
return exchange -> {
|
return exchange -> {
|
||||||
Request request = new DefaultRequest(exchange, strategies);
|
Request request = new DefaultRequest(exchange, strategies);
|
||||||
addAttributes(exchange, request);
|
addAttributes(exchange, request);
|
||||||
|
|
||||||
Optional<? extends HandlerFunction<?>> route = routerFunction.route(request);
|
Optional<? extends HandlerFunction<?>> route = routerFunction.route(request);
|
||||||
return Mono.justOrEmpty(route);
|
return Mono.justOrEmpty(route);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StrategiesSupplier defaultStrategies() {
|
|
||||||
return StrategiesSupplier.builder().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void addAttributes(ServerWebExchange exchange, Request request) {
|
private static void addAttributes(ServerWebExchange exchange, Request request) {
|
||||||
Map<String, Object> attributes = exchange.getAttributes();
|
Map<String, Object> attributes = exchange.getAttributes();
|
||||||
|
|
@ -218,4 +206,5 @@ public abstract class RouterFunctions {
|
||||||
static <T> HandlerFunction<T> cast(HandlerFunction<?> handlerFunction) {
|
static <T> HandlerFunction<T> cast(HandlerFunction<?> handlerFunction) {
|
||||||
return (HandlerFunction<T>) handlerFunction;
|
return (HandlerFunction<T>) handlerFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import org.springframework.web.reactive.result.view.ViewResolver;
|
||||||
* {@link #of(Supplier, Supplier, Supplier)}.
|
* {@link #of(Supplier, Supplier, Supplier)}.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see RouterFunctions#toHttpHandler(RouterFunction, StrategiesSupplier)
|
* @see RouterFunctions#toHttpHandler(RouterFunction, StrategiesSupplier)
|
||||||
* @see RouterFunctions#toHandlerMapping(RouterFunction, StrategiesSupplier)
|
* @see RouterFunctions#toHandlerMapping(RouterFunction, StrategiesSupplier)
|
||||||
|
|
@ -62,12 +63,35 @@ public interface StrategiesSupplier {
|
||||||
*/
|
*/
|
||||||
Supplier<Stream<ViewResolver>> viewResolvers();
|
Supplier<Stream<ViewResolver>> viewResolvers();
|
||||||
|
|
||||||
|
|
||||||
// Static methods
|
// Static methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a new {@code StrategiesSupplier} described by the given supplier functions. All
|
* Return a new {@code StrategiesSupplier} with default initialization.
|
||||||
* provided supplier function parameters can be {@code null} to indicate an empty stream is to
|
* @return the new {@code StrategiesSupplier}
|
||||||
* be returned.
|
*/
|
||||||
|
static StrategiesSupplier withDefaults() {
|
||||||
|
return builder().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@code StrategiesSupplier} based on the given
|
||||||
|
* {@linkplain ApplicationContext application context}.
|
||||||
|
* The returned supplier will search for all {@link HttpMessageReader}, {@link HttpMessageWriter},
|
||||||
|
* and {@link ViewResolver} instances in the given application context and return them for
|
||||||
|
* {@link #messageReaders()}, {@link #messageWriters()}, and {@link #viewResolvers()}
|
||||||
|
* respectively.
|
||||||
|
* @param applicationContext the application context to base the strategies on
|
||||||
|
* @return the new {@code StrategiesSupplier}
|
||||||
|
*/
|
||||||
|
static StrategiesSupplier of(ApplicationContext applicationContext) {
|
||||||
|
return builder(applicationContext).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new {@code StrategiesSupplier} described by the given supplier functions.
|
||||||
|
* All provided supplier function parameters can be {@code null} to indicate an empty
|
||||||
|
* stream is to be returned.
|
||||||
* @param messageReaders the supplier function for {@link HttpMessageReader} instances (can be {@code null})
|
* @param messageReaders the supplier function for {@link HttpMessageReader} instances (can be {@code null})
|
||||||
* @param messageWriters the supplier function for {@link HttpMessageWriter} instances (can be {@code null})
|
* @param messageWriters the supplier function for {@link HttpMessageWriter} instances (can be {@code null})
|
||||||
* @param viewResolvers the supplier function for {@link ViewResolver} instances (can be {@code null})
|
* @param viewResolvers the supplier function for {@link ViewResolver} instances (can be {@code null})
|
||||||
|
|
@ -82,17 +106,14 @@ public interface StrategiesSupplier {
|
||||||
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
||||||
return checkForNull(messageReaders);
|
return checkForNull(messageReaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Supplier<Stream<HttpMessageWriter<?>>> messageWriters() {
|
public Supplier<Stream<HttpMessageWriter<?>>> messageWriters() {
|
||||||
return checkForNull(messageWriters);
|
return checkForNull(messageWriters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Supplier<Stream<ViewResolver>> viewResolvers() {
|
public Supplier<Stream<ViewResolver>> viewResolvers() {
|
||||||
return checkForNull(viewResolvers);
|
return checkForNull(viewResolvers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> Supplier<Stream<T>> checkForNull(Supplier<Stream<T>> supplier) {
|
private <T> Supplier<Stream<T>> checkForNull(Supplier<Stream<T>> supplier) {
|
||||||
return supplier != null ? supplier : Stream::empty;
|
return supplier != null ? supplier : Stream::empty;
|
||||||
}
|
}
|
||||||
|
|
@ -100,16 +121,10 @@ public interface StrategiesSupplier {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
// Builder methods
|
||||||
* Return a mutable, empty builder for a {@code StrategiesSupplier}.
|
|
||||||
* @return the builder
|
|
||||||
*/
|
|
||||||
static Builder empty() {
|
|
||||||
return new DefaultStrategiesSupplierBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a mutable builder for a {@code StrategiesSupplier} with a default initialization.
|
* Return a mutable builder for a {@code StrategiesSupplier} with default initialization.
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
static Builder builder() {
|
static Builder builder() {
|
||||||
|
|
@ -127,13 +142,21 @@ public interface StrategiesSupplier {
|
||||||
* @param applicationContext the application context to base the strategies on
|
* @param applicationContext the application context to base the strategies on
|
||||||
* @return the builder
|
* @return the builder
|
||||||
*/
|
*/
|
||||||
static Builder applicationContext(ApplicationContext applicationContext) {
|
static Builder builder(ApplicationContext applicationContext) {
|
||||||
Assert.notNull(applicationContext, "'applicationContext' must not be null");
|
Assert.notNull(applicationContext, "ApplicationContext must not be null");
|
||||||
DefaultStrategiesSupplierBuilder builder = new DefaultStrategiesSupplierBuilder();
|
DefaultStrategiesSupplierBuilder builder = new DefaultStrategiesSupplierBuilder();
|
||||||
builder.applicationContext(applicationContext);
|
builder.applicationContext(applicationContext);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mutable, empty builder for a {@code StrategiesSupplier}.
|
||||||
|
* @return the builder
|
||||||
|
*/
|
||||||
|
static Builder empty() {
|
||||||
|
return new DefaultStrategiesSupplierBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mutable builder for a {@link StrategiesSupplier}.
|
* A mutable builder for a {@link StrategiesSupplier}.
|
||||||
|
|
@ -166,6 +189,6 @@ public interface StrategiesSupplier {
|
||||||
* @return the built strategies
|
* @return the built strategies
|
||||||
*/
|
*/
|
||||||
StrategiesSupplier build();
|
StrategiesSupplier build();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,18 +83,17 @@ public abstract class AbstractDispatcherHandlerInitializer implements WebApplica
|
||||||
Assert.notNull(applicationContext,
|
Assert.notNull(applicationContext,
|
||||||
"createApplicationContext() did not return an application " +
|
"createApplicationContext() did not return an application " +
|
||||||
"context for servlet [" + servletName + "]");
|
"context for servlet [" + servletName + "]");
|
||||||
|
|
||||||
refreshApplicationContext(applicationContext);
|
refreshApplicationContext(applicationContext);
|
||||||
registerCloseListener(servletContext, applicationContext);
|
registerCloseListener(servletContext, applicationContext);
|
||||||
|
|
||||||
WebHandler dispatcherHandler = createDispatcherHandler(applicationContext);
|
WebHandler dispatcherHandler = createDispatcherHandler(applicationContext);
|
||||||
Assert.notNull(dispatcherHandler,
|
Assert.notNull(dispatcherHandler,
|
||||||
"createDispatcherHandler() did not return a WebHandler for servlet ["
|
"createDispatcherHandler() did not return a WebHandler for servlet [" + servletName + "]");
|
||||||
+ servletName + "]");
|
|
||||||
|
|
||||||
ServletHttpHandlerAdapter handlerAdapter = createHandlerAdapter(dispatcherHandler);
|
ServletHttpHandlerAdapter handlerAdapter = createHandlerAdapter(dispatcherHandler);
|
||||||
Assert.notNull(handlerAdapter,
|
Assert.notNull(handlerAdapter,
|
||||||
"createHttpHandler() did not return a ServletHttpHandlerAdapter for servlet ["
|
"createHttpHandler() did not return a ServletHttpHandlerAdapter for servlet [" + servletName + "]");
|
||||||
+ servletName + "]");
|
|
||||||
|
|
||||||
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, handlerAdapter);
|
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, handlerAdapter);
|
||||||
Assert.notNull(registration,
|
Assert.notNull(registration,
|
||||||
|
|
@ -105,7 +104,6 @@ public abstract class AbstractDispatcherHandlerInitializer implements WebApplica
|
||||||
registration.addMapping(getServletMapping());
|
registration.addMapping(getServletMapping());
|
||||||
registration.setAsyncSupported(true);
|
registration.setAsyncSupported(true);
|
||||||
|
|
||||||
|
|
||||||
customizeRegistration(registration);
|
customizeRegistration(registration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,23 +174,21 @@ public abstract class AbstractDispatcherHandlerInitializer implements WebApplica
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a {@link ServletContextListener} that closes the given application context when
|
* Register a {@link ServletContextListener} that closes the given application context
|
||||||
* the servlet context is destroyed.
|
* when the servlet context is destroyed.
|
||||||
* @param servletContext the servlet context to listen to
|
* @param servletContext the servlet context to listen to
|
||||||
* @param applicationContext the application context that is to be closed when
|
* @param applicationContext the application context that is to be closed when
|
||||||
* {@code servletContext} is destroyed
|
* {@code servletContext} is destroyed
|
||||||
*/
|
*/
|
||||||
protected void registerCloseListener(ServletContext servletContext,
|
protected void registerCloseListener(ServletContext servletContext, ApplicationContext applicationContext) {
|
||||||
ApplicationContext applicationContext) {
|
|
||||||
|
|
||||||
if (applicationContext instanceof ConfigurableApplicationContext) {
|
if (applicationContext instanceof ConfigurableApplicationContext) {
|
||||||
ConfigurableApplicationContext context =
|
ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;
|
||||||
(ConfigurableApplicationContext) applicationContext;
|
|
||||||
ServletContextDestroyedListener listener = new ServletContextDestroyedListener(context);
|
ServletContextDestroyedListener listener = new ServletContextDestroyedListener(context);
|
||||||
servletContext.addListener(listener);
|
servletContext.addListener(listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class ServletContextDestroyedListener implements ServletContextListener {
|
private static class ServletContextDestroyedListener implements ServletContextListener {
|
||||||
|
|
||||||
private final ConfigurableApplicationContext applicationContext;
|
private final ConfigurableApplicationContext applicationContext;
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@ import org.springframework.http.ReactiveHttpOutputMessage;
|
||||||
import org.springframework.http.codec.HttpMessageReader;
|
import org.springframework.http.codec.HttpMessageReader;
|
||||||
import org.springframework.http.codec.HttpMessageWriter;
|
import org.springframework.http.codec.HttpMessageWriter;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
|
|
@ -52,7 +51,6 @@ public class StrategiesSupplierTests {
|
||||||
assertEquals(Optional.empty(), strategies.viewResolvers().get().findFirst());
|
assertEquals(Optional.empty(), strategies.viewResolvers().get().findFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ofSuppliers() {
|
public void ofSuppliers() {
|
||||||
HttpMessageReader<?> messageReader = new DummyMessageReader();
|
HttpMessageReader<?> messageReader = new DummyMessageReader();
|
||||||
|
|
@ -79,8 +77,7 @@ public class StrategiesSupplierTests {
|
||||||
applicationContext.registerSingleton("messageReader", DummyMessageReader.class);
|
applicationContext.registerSingleton("messageReader", DummyMessageReader.class);
|
||||||
applicationContext.refresh();
|
applicationContext.refresh();
|
||||||
|
|
||||||
StrategiesSupplier
|
StrategiesSupplier strategies = StrategiesSupplier.of(applicationContext);
|
||||||
strategies = StrategiesSupplier.applicationContext(applicationContext).build();
|
|
||||||
assertTrue(strategies.messageReaders().get()
|
assertTrue(strategies.messageReaders().get()
|
||||||
.allMatch(r -> r instanceof DummyMessageReader));
|
.allMatch(r -> r instanceof DummyMessageReader));
|
||||||
assertTrue(strategies.messageWriters().get()
|
assertTrue(strategies.messageWriters().get()
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,12 @@ public class ReactorHttpHandlerAdapter implements Function<HttpChannel, Mono<Voi
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(ReactorHttpHandlerAdapter.class);
|
private static Log logger = LogFactory.getLog(ReactorHttpHandlerAdapter.class);
|
||||||
|
|
||||||
|
private final HttpHandler delegate;
|
||||||
private final HttpHandler httpHandler;
|
|
||||||
|
|
||||||
|
|
||||||
public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
|
public ReactorHttpHandlerAdapter(HttpHandler delegate) {
|
||||||
Assert.notNull(httpHandler, "HttpHandler is required");
|
Assert.notNull(delegate, "HttpHandler delegate is required");
|
||||||
this.httpHandler = httpHandler;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -52,7 +51,8 @@ public class ReactorHttpHandlerAdapter implements Function<HttpChannel, Mono<Voi
|
||||||
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(channel.delegate().alloc());
|
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(channel.delegate().alloc());
|
||||||
ReactorServerHttpRequest adaptedRequest = new ReactorServerHttpRequest(channel, bufferFactory);
|
ReactorServerHttpRequest adaptedRequest = new ReactorServerHttpRequest(channel, bufferFactory);
|
||||||
ReactorServerHttpResponse adaptedResponse = new ReactorServerHttpResponse(channel, bufferFactory);
|
ReactorServerHttpResponse adaptedResponse = new ReactorServerHttpResponse(channel, bufferFactory);
|
||||||
return this.httpHandler.handle(adaptedRequest, adaptedResponse)
|
|
||||||
|
return this.delegate.handle(adaptedRequest, adaptedResponse)
|
||||||
.otherwise(ex -> {
|
.otherwise(ex -> {
|
||||||
logger.debug("Could not complete request", ex);
|
logger.debug("Could not complete request", ex);
|
||||||
channel.status(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
channel.status(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
|
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
|
||||||
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
|
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
|
||||||
import io.reactivex.netty.protocol.http.server.RequestHandler;
|
import io.reactivex.netty.protocol.http.server.RequestHandler;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
|
|
@ -42,13 +41,12 @@ public class RxNettyHttpHandlerAdapter implements RequestHandler<ByteBuf, ByteBu
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(RxNettyHttpHandlerAdapter.class);
|
private static Log logger = LogFactory.getLog(RxNettyHttpHandlerAdapter.class);
|
||||||
|
|
||||||
|
private final HttpHandler delegate;
|
||||||
private final HttpHandler httpHandler;
|
|
||||||
|
|
||||||
|
|
||||||
public RxNettyHttpHandlerAdapter(HttpHandler httpHandler) {
|
public RxNettyHttpHandlerAdapter(HttpHandler delegate) {
|
||||||
Assert.notNull(httpHandler, "'httpHandler' is required");
|
Assert.notNull(delegate, "HttpHandler delegate is required");
|
||||||
this.httpHandler = httpHandler;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -57,13 +55,15 @@ public class RxNettyHttpHandlerAdapter implements RequestHandler<ByteBuf, ByteBu
|
||||||
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.unsafeNettyChannel().alloc());
|
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.unsafeNettyChannel().alloc());
|
||||||
RxNettyServerHttpRequest adaptedRequest = new RxNettyServerHttpRequest(request, bufferFactory);
|
RxNettyServerHttpRequest adaptedRequest = new RxNettyServerHttpRequest(request, bufferFactory);
|
||||||
RxNettyServerHttpResponse adaptedResponse = new RxNettyServerHttpResponse(response, bufferFactory);
|
RxNettyServerHttpResponse adaptedResponse = new RxNettyServerHttpResponse(response, bufferFactory);
|
||||||
Publisher<Void> result = this.httpHandler.handle(adaptedRequest, adaptedResponse)
|
|
||||||
|
Publisher<Void> result = this.delegate.handle(adaptedRequest, adaptedResponse)
|
||||||
.otherwise(ex -> {
|
.otherwise(ex -> {
|
||||||
logger.debug("Could not complete request", ex);
|
logger.debug("Could not complete request", ex);
|
||||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
})
|
})
|
||||||
.doOnSuccess(aVoid -> logger.debug("Successfully completed request"));
|
.doOnSuccess(aVoid -> logger.debug("Successfully completed request"));
|
||||||
|
|
||||||
return RxJava1Adapter.publisherToObservable(result);
|
return RxJava1Adapter.publisherToObservable(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,37 +45,31 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
|
||||||
|
|
||||||
|
|
||||||
public UndertowHttpHandlerAdapter(HttpHandler delegate) {
|
public UndertowHttpHandlerAdapter(HttpHandler delegate) {
|
||||||
Assert.notNull(delegate, "'delegate' is required");
|
Assert.notNull(delegate, "HttpHandler delegate is required");
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setDataBufferFactory(DataBufferFactory dataBufferFactory) {
|
public void setDataBufferFactory(DataBufferFactory dataBufferFactory) {
|
||||||
Assert.notNull(dataBufferFactory, "'dataBufferFactory' must not be null");
|
Assert.notNull(dataBufferFactory, "DataBufferFactory must not be null");
|
||||||
this.dataBufferFactory = dataBufferFactory;
|
this.dataBufferFactory = dataBufferFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleRequest(HttpServerExchange exchange) throws Exception {
|
public void handleRequest(HttpServerExchange exchange) throws Exception {
|
||||||
|
ServerHttpRequest request = new UndertowServerHttpRequest(exchange, this.dataBufferFactory);
|
||||||
ServerHttpRequest request =
|
ServerHttpResponse response = new UndertowServerHttpResponse(exchange, this.dataBufferFactory);
|
||||||
new UndertowServerHttpRequest(exchange, this.dataBufferFactory);
|
|
||||||
|
|
||||||
ServerHttpResponse response =
|
|
||||||
new UndertowServerHttpResponse(exchange, this.dataBufferFactory);
|
|
||||||
|
|
||||||
this.delegate.handle(request, response).subscribe(new Subscriber<Void>() {
|
this.delegate.handle(request, response).subscribe(new Subscriber<Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSubscribe(Subscription subscription) {
|
public void onSubscribe(Subscription subscription) {
|
||||||
subscription.request(Long.MAX_VALUE);
|
subscription.request(Long.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNext(Void aVoid) {
|
public void onNext(Void aVoid) {
|
||||||
// no op
|
// no op
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Throwable ex) {
|
public void onError(Throwable ex) {
|
||||||
logger.debug("Could not complete request", ex);
|
logger.debug("Could not complete request", ex);
|
||||||
|
|
@ -84,7 +78,6 @@ public class UndertowHttpHandlerAdapter implements io.undertow.server.HttpHandle
|
||||||
}
|
}
|
||||||
exchange.endExchange();
|
exchange.endExchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() {
|
public void onComplete() {
|
||||||
logger.debug("Successfully completed request");
|
logger.debug("Successfully completed request");
|
||||||
|
|
|
||||||
|
|
@ -182,12 +182,8 @@ For the bootstrap code start with:
|
||||||
[source,java,indent=0]
|
[source,java,indent=0]
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
ApplicationContext context = new AnnotationConfigApplicationContext(WebReactiveConfiguration.class); // (1)
|
||||||
context.register(WebReactiveConfiguration.class); // (1)
|
HttpHandler handler = DispatcherHandler.toHttpHandler(context); // (2)
|
||||||
context.refresh();
|
|
||||||
|
|
||||||
DispatcherHandler dispatcherHandler = new DispatcherHandler(context); // (2)
|
|
||||||
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(dispatcherHandler).build();
|
|
||||||
----
|
----
|
||||||
|
|
||||||
The above loads default Spring Web Reactive config (1), then creates a
|
The above loads default Spring Web Reactive config (1), then creates a
|
||||||
|
|
@ -199,22 +195,22 @@ An `HttpHandler` can then be installed in each supported runtime:
|
||||||
[subs="verbatim,quotes"]
|
[subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
// Tomcat and Jetty (also see notes below)
|
// Tomcat and Jetty (also see notes below)
|
||||||
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
|
HttpServlet servlet = new ServletHttpHandlerAdapter(handler);
|
||||||
...
|
...
|
||||||
|
|
||||||
// Reactor Netty
|
// Reactor Netty
|
||||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
|
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
|
||||||
HttpServer server = HttpServer.create(host, port);
|
HttpServer server = HttpServer.create(host, port);
|
||||||
server.startAndAwait(adapter);
|
server.startAndAwait(adapter);
|
||||||
|
|
||||||
// RxNetty
|
// RxNetty
|
||||||
RxNettyHttpHandlerAdapter handlerAdapter = new RxNettyHttpHandlerAdapter(httpHandler);
|
RxNettyHttpHandlerAdapter adapter = new RxNettyHttpHandlerAdapter(handler);
|
||||||
HttpServer server = HttpServer.newServer(new InetSocketAddress(host, port));
|
HttpServer server = HttpServer.newServer(new InetSocketAddress(host, port));
|
||||||
server.startAndAwait(adapter);
|
server.startAndAwait(adapter);
|
||||||
|
|
||||||
// Undertow
|
// Undertow
|
||||||
HttpHandler handler = new UndertowHttpHandlerAdapter(httpHandler);
|
UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler);
|
||||||
Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(httpHandler).build();
|
Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build();
|
||||||
server.start();
|
server.start();
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue