从浏览器请求到WebApplication响应“hello world”的过程是什么

前话

在编写SpringBoot Web程序完后,运行这个web程序,然后用http请求工具发送请求,然后程序对应的请求处理器就会执行相应的操作;那么,这个http请求是如何被web程序所接受的,又是如何路由到我们对应的http handler上的?

Web容器

在使用SpringBoot有一大好处——再也不用外部的web容器了,它自身整合了目前流行的几大web容器,当然你也可以实现自己的web容器

SpringBoot关于Web容器相关的代码在org.springframework.boot.web.embedded包中,该包下目前有四种web容器——jettynettytomcat以及undertow;在这里我使用的是nettyweb容器

ReactiveWebServerApplicationContext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start reactive web server",
ex);
}
}

private void createWebServer() {
ServerManager serverManager = this.serverManager;
if (serverManager == null) {
this.serverManager = ServerManager.get(getWebServerFactory());
}
initPropertySources();
}

这个createWebServer方法的执行表示正式开始对WebServer进行相应的前期初始化,因为该方法调用的时期位于ApplicationContextonRefresh时期,因此ServerManager == null,所以前去执行ServerManager.get(getWebServerFactory())进行创建一个ServerManager

1
2
3
4
5
6
7
8
9
10
private ServerManager(ReactiveWebServerFactory factory) {
this.handler = this::handleUninitialized;
this.server = factory.getWebServer(this);
}

private Mono<Void> handleUninitialized(ServerHttpRequest request,
ServerHttpResponse response) {
throw new IllegalStateException(
"The HttpHandler has not yet been initialized");
}

因此此时整个程序处于onRefresh状态,Handler尚未被Spring加载,此处便用handleUninitialized进行代替(ServerManager的handler此时是一个lambda表达式),在这里又可以看到,需要获取一个WebServer

NettyReactiveWebServerFactory

这是一个创建netty web容器的工厂,通过调用getWebServer方法即可获得一个web容器

1
2
3
4
5
6
7
@Override
public WebServer getWebServer(HttpHandler httpHandler) {
HttpServer httpServer = createHttpServer();
ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
httpHandler);
return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
}

这里需要获取两个对象,一个是HttpServer,另一个是获取http请求的处理器handler;然后创建一个NettyWebServer,这个就是最终的Web容器

现在再次回到ReactiveWebServerApplicationContext这个对象中,此时onRefresh中相应的操作均已完成,接着就是finishRefresh,此步骤,将会正式启动我们的WebServer

ReactiveWebServerApplicationContext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void finishRefresh() {
super.finishRefresh();
WebServer webServer = startReactiveWebServer();
if (webServer != null) {
publishEvent(new ReactiveWebServerInitializedEvent(webServer, this));
}
}

private WebServer startReactiveWebServer() {
ServerManager serverManager = this.serverManager;
ServerManager.start(serverManager, this::getHttpHandler);
return ServerManager.getWebServer(serverManager);
}

经过此前的onRefresh阶段,this.serverManager已经不为null了,因此执行start方法启动WebServer;并且进行Http Handler的加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Return the {@link HttpHandler} that should be used to process the reactive web
* server. By default this method searches for a suitable bean in the context itself.
* @return a {@link HttpHandler} (never {@code null}
*/
protected HttpHandler getHttpHandler() {
// Use bean names so that we don't consider the hierarchy
String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean.");
}
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
}

加载完所有的Handler之后,正式启动WebServer,并且重新为handler赋值(此时的HandlerHttpWebHandlerAdapter对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// ServerManager
public static void start(ServerManager manager, Supplier<HttpHandler> handlerSupplier) {
if (manager != null && manager.server != null) {
manager.handler = handlerSupplier.get();
manager.server.start();
}
}

// NettyWebServer
@Override
public void start() throws WebServerException {
if (this.disposableServer == null) {
try {
this.disposableServer = startHttpServer();
}
catch (Exception ex) {
ChannelBindException bindException = findBindException(ex);
if (bindException != null) {
throw new PortInUseException(bindException.localPort());
}
throw new WebServerException("Unable to start Netty", ex);
}
logger.info("Netty started on port(s): " + getPort());
startDaemonAwaitThread(this.disposableServer);
}
}

private DisposableServer startHttpServer() {
if (this.lifecycleTimeout != null) {
return this.httpServer.handle(this.handlerAdapter)
.bindNow(this.lifecycleTimeout);
}
return this.httpServer.handle(this.handlerAdapter).bindNow();
}

至此整个WebServer容器算是启动完成

请求处理

涉及Http请求处理那就要来看ReactorHttpHandlerAdapterHttpWebHandlerAdapter以及DispatcherHandler了,先来看ReactorHttpHandlerAdapter

ReactorHttpHandlerAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest, HttpServerResponse, Mono<Void>> {

private static final Log logger = HttpLogging.forLogName(ReactorHttpHandlerAdapter.class);


private final HttpHandler httpHandler;


public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
Assert.notNull(httpHandler, "HttpHandler must not be null");
this.httpHandler = httpHandler;
}


@Override
public Mono<Void> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
try {
ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);

if (request.getMethod() == HttpMethod.HEAD) {
response = new HttpHeadResponseDecorator(response);
}

return this.httpHandler.handle(request, response)
.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
}
catch (URISyntaxException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to get request URI: " + ex.getMessage());
}
reactorResponse.status(HttpResponseStatus.BAD_REQUEST);
return Mono.empty();
}
}

}

可以看出,ReactorHttpHandlerAdapter是最先接收到请求的(具体如何调用到这里的需要结合reactor.netty,这里不细说)然后调用HttpHandler,将请求下发至对应的HttpHandler(即HttpWebHandlerAdapter

HttpWebHandlerAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
if (this.forwardedHeaderTransformer != null) {
request = this.forwardedHeaderTransformer.apply(request);
}
ServerWebExchange exchange = createExchange(request, response);

LogFormatUtils.traceDebug(logger, traceOn ->
exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));

return getDelegate().handle(exchange)
.doOnSuccess(aVoid -> logResponse(exchange))
.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
.then(Mono.defer(response::setComplete));
}

protected ServerWebExchange createExchange(ServerHttpRequest request, ServerHttpResponse response) {
return new DefaultServerWebExchange(request, response, this.sessionManager,
getCodecConfigurer(), getLocaleContextResolver(), this.applicationContext);
}

在这里会对ServerHttpRequest request, ServerHttpResponse response进行包装成为ServerWebExchange,然后下发到WebHabdler(此处为ExceptionHandlingWebHandler),这里就是Spring能够拦截到我们程序中出现的异常的原因。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public Mono<Void> handle(ServerWebExchange exchange) {

Mono<Void> completion;
try {
// 处理 http 请求
completion = super.handle(exchange);
}
catch (Throwable ex) {
completion = Mono.error(ex);
}

for (WebExceptionHandler handler : this.exceptionHandlers) {
completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
}

return completion;
}

这时,super.handler跳转到了FilteringWebHandler(此时就是责任链模式了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private final DefaultWebFilterChain chain;

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
return this.chain.filter(exchange);
}

@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() ->
this.currentFilter != null && this.next != null ?
this.currentFilter.filter(exchange, this.next) :
this.handler.handle(exchange));
}

Spring对于Http请求采用的是责任链模式,会判断当前的filter以及下一个filter,只要有一个为null直接结束责任链,进入handler;而进入责任链模式后,第一个遇到的就是DispatcherHandler`!

DispatcherHandler

它的内部有三个List`

{@link HandlerMapping} – map requests to handler objects

{@link HandlerAdapter} – for using any handler interface

{@link HandlerResultHandler} – process handler return values

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}

由注解可知,这里就是进行Http请求分发至相应的请求处理器了,这里截了图以便更为清晰的了解

DispatcherHandler

接着重要的就是如何将请求路由到对应的处理器了,这里是由HandlerMapping.getHandler实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
if (logger.isDebugEnabled()) {
logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
}
if (CorsUtils.isCorsRequest(exchange.getRequest())) {
CorsConfiguration configA = this.corsConfigurationSource.getCorsConfiguration(exchange);
CorsConfiguration configB = getCorsConfiguration(handler, exchange);
CorsConfiguration config = (configA != null ? configA.combine(configB) : configB);
if (!getCorsProcessor().process(config, exchange) ||
CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return REQUEST_HANDLED_HANDLER;
}
}
return handler;
});
}

根据代码可以看出,在执行函数getHandlerInternal(exchange)时已经找出了对应的handler了,此操作的执行者为RouterFunctionMapping

1
2
3
4
5
6
7
8
9
10
11
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
if (this.routerFunction != null) {
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
return this.routerFunction.route(request)
.doOnNext(handler -> setAttributes(exchange.getAttributes(), request, handler));
}
else {
return Mono.empty();
}
}

此处route函数的执行者会采用DefaultRouterFunction作为执行者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private final RequestPredicate predicate;
private final HandlerFunction<T> handlerFunction;

@Override
public Mono<HandlerFunction<T>> route(ServerRequest request) {
if (this.predicate.test(request)) {
if (logger.isTraceEnabled()) {
String logPrefix = request.exchange().getLogPrefix();
logger.trace(logPrefix + String.format("Matched %s", this.predicate));
}
return Mono.just(this.handlerFunction);
}
else {
return Mono.empty();
}
}

可以看到这里有一个this.predicate.test(request),而这个就是最核心的了,通过RequestPredicate对请求进行判断,是否符合要求,符合要求将HandlerFunction向外发布出去。

RequestPredicate有多个实现子类,所有的子类都在org.springframework.web.reactive.function.server.RequestPredicates下,有关于Http请求类型(get、post、put等等)的验证HttpMethodPredicate;有关于请求URL的验证PathPatternPredicate

主要说一下PathPatternPredicate

PathPatternPredicate

我的代码

1
2
3
4
5
6
7
8
9
10
@Bean(value = "NacosRouter")
public RouterFunction NacosRouter() {
return route(
POST(StringConst.API).and(accept(MediaType.APPLICATION_JSON_UTF8))
.and(contentType(MediaType.APPLICATION_JSON_UTF8)), nacosHandler::post)
.andRoute(PUT(StringConst.API).and(accept(MediaType.APPLICATION_JSON_UTF8))
.and(contentType(MediaType.APPLICATION_JSON_UTF8)), nacosHandler::put)
.andRoute(GET(StringConst.API).and(accept(MediaType.APPLICATION_JSON_UTF8))
, nacosHandler::get);
}

这段代码是我的web程序关于路由设定的

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public boolean test(ServerRequest request) {
PathContainer pathContainer = request.pathContainer();
PathPattern.PathMatchInfo info = this.pattern.matchAndExtract(pathContainer);
traceMatch("Pattern", this.pattern.getPatternString(), request.path(), info != null);
if (info != null) {
mergeAttributes(request, info.getUriVariables(), this.pattern);
return true;
}
else {
return false;
}
}

根据你设定的请求URL创建一个PathContainer对象,该对象是对URL进行结构化的表示,然后调用

1
PathPattern.PathMatchInfo info = this.pattern.matchAndExtract(pathContainer);

进行实际请求URL与设定的URL信息进行比对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Nullable
public PathMatchInfo matchAndExtract(PathContainer pathContainer) {
if (this.head == null) {
return hasLength(pathContainer) &&
!(this.matchOptionalTrailingSeparator && pathContainerIsJustSeparator(pathContainer))
? null : PathMatchInfo.EMPTY;
}
else if (!hasLength(pathContainer)) {
if (this.head instanceof WildcardTheRestPathElement || this.head instanceof CaptureTheRestPathElement) {
pathContainer = EMPTY_PATH; // Will allow CaptureTheRest to bind the variable to empty
}
else {
return null;
}
}
MatchingContext matchingContext = new MatchingContext(pathContainer, true);
return this.head.matches(0, matchingContext) ? matchingContext.getPathMatchResult() : null;
}

通过对返回的PathMatchInfo是否为null来对本次请求匹配做判断,具体的匹配模式有很多种,具体的实现看PathElement的子类即可。

经过以上步骤之后,再次回到DispatcherHandlerhandler方法

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(createNotFoundError())
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}

这时执行完了mapping.getHandler(exchange)方法了,然后根据返回的handler是否为空决定是否创建Http Not Found错误;如果handler不为空,就是将请求信息送入对应的handler去处理了以及获取handler处理后的返回信息进行拦截返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult ->
getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
}

private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this.resultHandlers != null) {
for (HandlerResultHandler resultHandler : this.resultHandlers) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}