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() + "]"); logger.debug("Processing " + request.getMethod() + " request for [" + request.getURI() + "]");
} }
Object handler = getHandler(request); Publisher<Object> handlerPublisher = getHandler(request);
if (handler == null) { if (handlerPublisher == null) {
// No exception handling mechanism yet // No exception handling mechanism yet
response.setStatusCode(HttpStatus.NOT_FOUND); response.setStatusCode(HttpStatus.NOT_FOUND);
response.writeHeaders(); response.writeHeaders();
return Publishers.empty(); return Publishers.empty();
} }
Publisher<HandlerResult> resultPublisher = Publishers.concatMap(handlerPublisher, handler -> {
HandlerAdapter handlerAdapter = getHandlerAdapter(handler); HandlerAdapter handlerAdapter = getHandlerAdapter(handler);
if (handlerAdapter == null) { return handlerAdapter.handle(request, response, handler);
return Publishers.error(new IllegalStateException("No HandlerAdapter for " + handler)); });
}
Publisher<HandlerResult> resultPublisher = handlerAdapter.handle(request, response, handler);
return Publishers.concatMap(resultPublisher, result -> { return Publishers.concatMap(resultPublisher, result -> {
for (HandlerResultHandler resultHandler : resultHandlers) { HandlerResultHandler handler = getResultHandler(result);
if (resultHandler.supports(result)) { return handler.handleResult(request, response, result);
return resultHandler.handleResult(request, response, result);
}
}
return Publishers.error(new IllegalStateException(
"No HandlerResultHandler for " + result.getValue()));
}); });
} }
protected Object getHandler(ReactiveServerHttpRequest request) { protected Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
Object handler = null;
for (HandlerMapping handlerMapping : this.handlerMappings) { for (HandlerMapping handlerMapping : this.handlerMappings) {
handler = handlerMapping.getHandler(request); Publisher<Object> handlerPublisher = handlerMapping.getHandler(request);
if (handler != null) { if (handlerPublisher != null) {
break; return handlerPublisher;
} }
} }
return handler; return null;
} }
protected HandlerAdapter getHandlerAdapter(Object handler) { protected HandlerAdapter getHandlerAdapter(Object handler) {
@ -141,7 +133,16 @@ public class DispatcherHandler implements ReactiveHttpHandler, ApplicationContex
return handlerAdapter; 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; package org.springframework.web.reactive;
import org.reactivestreams.Publisher;
import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.http.server.ReactiveServerHttpRequest;
/** /**
@ -23,6 +25,6 @@ import org.springframework.http.server.ReactiveServerHttpRequest;
*/ */
public interface HandlerMapping { 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.HashMap;
import java.util.Map; import java.util.Map;
import org.reactivestreams.Publisher;
import reactor.Publishers;
import org.springframework.http.server.ReactiveServerHttpRequest; import org.springframework.http.server.ReactiveServerHttpRequest;
import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.HandlerMapping;
@ -39,8 +42,10 @@ public class SimpleUrlHandlerMapping implements HandlerMapping {
@Override @Override
public Object getHandler(ReactiveServerHttpRequest request) { public Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
return this.handlerMap.get(request.getURI().getPath()); 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.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.Publishers;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -92,15 +94,16 @@ public class RequestMappingHandlerMapping implements HandlerMapping,
} }
@Override @Override
public Object getHandler(ReactiveServerHttpRequest request) { public Publisher<Object> getHandler(ReactiveServerHttpRequest request) {
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : this.methodMap.entrySet()) { for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : this.methodMap.entrySet()) {
RequestMappingInfo info = entry.getKey(); RequestMappingInfo info = entry.getKey();
if (info.matchesRequest(request)) { if (info.matchesRequest(request)) {
HandlerMethod handlerMethod = entry.getValue();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Mapped " + request.getMethod() + " " + 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; return null;

View File

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