HandlerMapping is now asynchronous

This commit is contained in:
Rossen Stoyanchev 2015-11-24 17:29:37 -05:00
parent dc57e2621c
commit d319edba28
5 changed files with 59 additions and 34 deletions

View File

@ -98,41 +98,33 @@ public class DispatcherHandler implements ReactiveHttpHandler, ApplicationContex
logger.debug("Processing " + request.getMethod() + " request for [" + request.getURI() + "]");
}
Object handler = getHandler(request);
if (handler == null) {
Publisher<Object> handlerPublisher = getHandler(request);
if (handlerPublisher == null) {
// No exception handling mechanism yet
response.setStatusCode(HttpStatus.NOT_FOUND);
response.writeHeaders();
return Publishers.empty();
}
HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
if (handlerAdapter == null) {
return Publishers.error(new IllegalStateException("No HandlerAdapter for " + handler));
}
Publisher<HandlerResult> resultPublisher = handlerAdapter.handle(request, response, handler);
Publisher<HandlerResult> resultPublisher = Publishers.concatMap(handlerPublisher, handler -> {
HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
return handlerAdapter.handle(request, response, handler);
});
return Publishers.concatMap(resultPublisher, result -> {
for (HandlerResultHandler resultHandler : resultHandlers) {
if (resultHandler.supports(result)) {
return resultHandler.handleResult(request, response, result);
}
}
return Publishers.error(new IllegalStateException(
"No HandlerResultHandler for " + result.getValue()));
HandlerResultHandler handler = getResultHandler(result);
return handler.handleResult(request, response, result);
});
}
protected Object getHandler(ReactiveServerHttpRequest request) {
Object handler = null;
protected Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
for (HandlerMapping handlerMapping : this.handlerMappings) {
handler = handlerMapping.getHandler(request);
if (handler != null) {
break;
Publisher<Object> handlerPublisher = handlerMapping.getHandler(request);
if (handlerPublisher != null) {
return handlerPublisher;
}
}
return handler;
return null;
}
protected HandlerAdapter getHandlerAdapter(Object handler) {
@ -141,7 +133,16 @@ public class DispatcherHandler implements ReactiveHttpHandler, ApplicationContex
return handlerAdapter;
}
}
return null;
throw new IllegalStateException("No HandlerAdapter: " + handler);
}
protected HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
for (HandlerResultHandler resultHandler : resultHandlers) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
throw new IllegalStateException("No HandlerResultHandler: " + handlerResult.getValue());
}
}

View File

@ -16,6 +16,8 @@
package org.springframework.web.reactive;
import org.reactivestreams.Publisher;
import org.springframework.http.server.ReactiveServerHttpRequest;
/**
@ -23,6 +25,6 @@ import org.springframework.http.server.ReactiveServerHttpRequest;
*/
public interface HandlerMapping {
Object getHandler(ReactiveServerHttpRequest request);
Publisher<Object> getHandler(ReactiveServerHttpRequest request);
}

View File

@ -19,6 +19,9 @@ package org.springframework.web.reactive.handler;
import java.util.HashMap;
import java.util.Map;
import org.reactivestreams.Publisher;
import reactor.Publishers;
import org.springframework.http.server.ReactiveServerHttpRequest;
import org.springframework.web.reactive.HandlerMapping;
@ -39,8 +42,10 @@ public class SimpleUrlHandlerMapping implements HandlerMapping {
@Override
public Object getHandler(ReactiveServerHttpRequest request) {
return this.handlerMap.get(request.getURI().getPath());
public Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
String path = request.getURI().getPath();
Object handler = this.handlerMap.get(path);
return (handler != null ? Publishers.just(handler) : null);
}
}

View File

@ -27,6 +27,8 @@ import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.Publishers;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
@ -92,15 +94,16 @@ public class RequestMappingHandlerMapping implements HandlerMapping,
}
@Override
public Object getHandler(ReactiveServerHttpRequest request) {
public Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : this.methodMap.entrySet()) {
RequestMappingInfo info = entry.getKey();
if (info.matchesRequest(request)) {
HandlerMethod handlerMethod = entry.getValue();
if (logger.isDebugEnabled()) {
logger.debug("Mapped " + request.getMethod() + " " +
request.getURI().getPath() + " to [" + entry.getValue() + "]");
request.getURI().getPath() + " to [" + handlerMethod + "]");
}
return entry.getValue();
return Publishers.just(handlerMethod);
}
}
return null;

View File

@ -19,10 +19,13 @@ package org.springframework.web.reactive.method.annotation;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.rx.Streams;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@ -34,6 +37,7 @@ import org.springframework.web.context.support.StaticWebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* @author Sebastien Deleuze
@ -56,19 +60,29 @@ public class RequestMappingHandlerMappingTests {
@Test
public void path() throws Exception {
ReactiveServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "boo");
HandlerMethod handler = (HandlerMethod) this.mapping.getHandler(request);
assertEquals(TestController.class.getMethod("boo"), handler.getMethod());
Publisher<?> handlerPublisher = this.mapping.getHandler(request);
HandlerMethod handlerMethod = toHandlerMethod(handlerPublisher);
assertEquals(TestController.class.getMethod("boo"), handlerMethod.getMethod());
}
@Test
public void method() throws Exception {
ReactiveServerHttpRequest request = new MockServerHttpRequest(HttpMethod.POST, "foo");
HandlerMethod handler = (HandlerMethod) this.mapping.getHandler(request);
assertEquals(TestController.class.getMethod("postFoo"), handler.getMethod());
Publisher<?> handlerPublisher = this.mapping.getHandler(request);
HandlerMethod handlerMethod = toHandlerMethod(handlerPublisher);
assertEquals(TestController.class.getMethod("postFoo"), handlerMethod.getMethod());
request = new MockServerHttpRequest(HttpMethod.GET, "foo");
handler = (HandlerMethod) this.mapping.getHandler(request);
assertEquals(TestController.class.getMethod("getFoo"), handler.getMethod());
handlerPublisher = this.mapping.getHandler(request);
handlerMethod = toHandlerMethod(handlerPublisher);
assertEquals(TestController.class.getMethod("getFoo"), handlerMethod.getMethod());
}
private HandlerMethod toHandlerMethod(Publisher<?> handlerPublisher) throws InterruptedException {
assertNotNull(handlerPublisher);
List<?> handlerList = Streams.wrap(handlerPublisher).toList().await(5, TimeUnit.SECONDS);
assertEquals(1, handlerList.size());
return (HandlerMethod) handlerList.get(0);
}