在本系列的上一篇文章中,我们介绍了Reactive Web服务器NettyWebServer的创建,这一篇文章,我们讲解该Reactive Web服务器是如何启动的。它对应于AnnotationConfigReactiveWebServerApplicationContext基类ReactiveWebServerApplicationContext的方法
startReactiveWebServer,被finishRefresh方法在缺省流程逻辑后调用:
// ReactiveWebServerApplicationContext 代码片段
@Override
protected void finishRefresh() {
super.finishRefresh(); // 调用基类定义的通用 finishRefresh 逻辑
// 启动 Reactive Web 服务器,并发布相应事件
// 这是 ReactiveWebServerApplicationContext 针对 WebFlux 环境的扩展逻辑
WebServer webServer = startReactiveWebServer();
if (webServer != null) {
publishEvent(new ReactiveWebServerInitializedEvent(webServer, this));
}
}
方法startReactiveWebServer实现如下 :
// ReactiveWebServerApplicationContext 代码片段
private WebServer startReactiveWebServer() {
ServerManager serverManager = this.serverManager;
// 使用静态方法 ServerManager#start 启动 Reactive WebServer,
// HttpHandler 由当前应用上下文的方法 getHttpHandler 提供
ServerManager.start(serverManager, this::getHttpHandler);
// 获取 serverManager 的属性 server
return ServerManager.getWebServer(serverManager);
}
startReactiveWebServer方法实现有两个要点 :
- 真正的启动工作通过调用
ServerManager.start来完成; - 调用
ServerManager.start时其参数Supplier<HttpHandler>使用当前ReactiveWebServerApplicationContext实例的方法getHttpHandler;
我们逐一来分析。
1. ServerManager#start
// ReactiveWebServerApplicationContext 内嵌类 ServerManager 代码片段
public static void start(ServerManager manager, Supplier<HttpHandler> handlerSupplier) {
if (manager != null && manager.server != null) {
// 将指定 ServerManager manager 的属性 handler设置成参数 handlerSupplier 所指定的
// HttpHandler
manager.handler = handlerSupplier.get();
// 调用 指定 ServerManager manager 中的 WebServer server 的启动逻辑
manager.server.start();
}
}
这里关于WebServer#start的启动,需要参考NettyWebServer :
package org.springframework.boot.web.embedded.netty;
// 省略 import 行
public class NettyWebServer implements WebServer {
private static final Log logger = LogFactory.getLog(NettyWebServer.class);
private final HttpServer httpServer;
private final ReactorHttpHandlerAdapter handlerAdapter;
private final Duration lifecycleTimeout;
private DisposableServer disposableServer;
// 构造函数
// 从上一篇的分析我们已经知道,这里 ReactorHttpHandlerAdapter 其实包装了一个 HttpHandler,
// 而该 HttpHandler 来自应用上下文对象 ReactiveWebServerApplicationContext 的方法 getHttpHandler
public NettyWebServer(HttpServer httpServer, ReactorHttpHandlerAdapter handlerAdapter,
Duration lifecycleTimeout) {
Assert.notNull(httpServer, "HttpServer must not be null");
Assert.notNull(handlerAdapter, "HandlerAdapter must not be null");
this.httpServer = httpServer;
this.handlerAdapter = handlerAdapter;
this.lifecycleTimeout = lifecycleTimeout;
}
@Override
public void start() throws WebServerException {
if (this.disposableServer == null) {
try {
// 启动 Reactive Web Server
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);
}
// 启动一个非后台线程,保持阻塞状态以确保Reactive Web Server 处于
// 持续服务状态
logger.info("Netty started on port(s): " + getPort());
startDaemonAwaitThread(this.disposableServer);
}
}
// 启动 Reactive Web 服务器,也就是 this.httpServer
// 1. 关联 Http 请求处理器 handlerAdapter
// 2. 服务端口绑定
private DisposableServer startHttpServer() {
if (this.lifecycleTimeout != null) {
// 设置了超时参数时的启动
return this.httpServer.handle(this.handlerAdapter).bindNow(this.lifecycleTimeout);
}
// 未设置超时参数时的启动 (缺省情况)
return this.httpServer.handle(this.handlerAdapter).bindNow();
}
private ChannelBindException findBindException(Exception ex) {
Throwable candidate = ex;
while (candidate != null) {
if (candidate instanceof ChannelBindException) {
return (ChannelBindException) candidate;
}
candidate = candidate.getCause();
}
return null;
}
private void startDaemonAwaitThread(DisposableServer disposableServer) {
Thread awaitThread = new Thread("server") {
@Override
public void run() {
// 使 Reactive Web Server 处于无限阻塞状态
disposableServer.onDispose().block();
}
};
awaitThread.setContextClassLoader(getClass().getClassLoader());
// 设置为前台线程并启动
awaitThread.setDaemon(false);
awaitThread.start();
}
@Override
public void stop() throws WebServerException {
if (this.disposableServer != null) {
if (this.lifecycleTimeout != null) {
this.disposableServer.disposeNow(this.lifecycleTimeout);
}
else {
this.disposableServer.disposeNow();
}
this.disposableServer = null;
}
}
@Override
public int getPort() {
if (this.disposableServer != null) {
return this.disposableServer.port();
}
return 0;
}
}
从上面的代码可见,启动过程并不复杂,总结起来就是 :
- 启动
Reactive Web服务器;
启动
NettyWebServer所包装的Web Server,其实是一个HttpServer,主要是服务端端口绑定动作,并将其包装成一个DisposableServer;
- 启动一个前台线程阻塞等待
Reactive Web服务器被释放;
该启动过程涉及到的主要是以Reactor Netty为中心的组件,看起来似乎跟Spring没有太多关系,但实际上,上述Netty Web服务器启动过程中一个重要参数ReactorHttpHandlerAdapter,代表了请求的处理逻辑,却正是来自Spring,这就是接下来我们要分析的ReactiveWebServerApplicationContext#getHttpHandler。
2. ReactiveWebServerApplicationContext#getHttpHandler
// 获取容器中有且仅有的一个类型为 HttpHandler 的 bean ,
// 如果容器中不存在该类型的 bean 或者有多个则抛出异常
protected HttpHandler getHttpHandler() {
// Use bean names so that we don't consider the hierarchy
// 从容器获取所有类型为 HttpHandler 的 bean
String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
// 如果容器中不存在类型为 HttpHandler 的 bean 则抛出异常
if (beanNames.length == 0) {
throw new ApplicationContextException(
"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean.");
}
// 如果容器中存在多个 HttpHandler bean 则抛出异常
if (beanNames.length > 1) {
throw new ApplicationContextException(
"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : "
+ StringUtils.arrayToCommaDelimitedString(beanNames));
}
// 获取容器中有且仅有的一个类型为 HttpHandler 的 bean
return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
}
从方法getHttpHandler的逻辑来看,它要求容器中必须存在并且仅存在一个类型为HttpHandler的bean组件,如果容器中不存在该类型的bean 或者有多个则抛出异常。实际上,在本系列文章例子应用中,getHttpHandler方法会正常获取一个类型为HttpHandler的bean组件,bean名称为httpHandler,实现类为HttpWebHandlerAdapter。
那么,这个bean httpHandler又来自哪里呢?这时候,我们要看Spring Boot的自动配置机制HttpHandlerAutoConfiguration了。
2.1 自动配置HttpHandlerAutoConfiguration
package org.springframework.boot.autoconfigure.web.reactive;
// 省略 import
@Configuration
@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnMissingBean(HttpHandler.class)
@AutoConfigureAfter({ WebFluxAutoConfiguration.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class HttpHandlerAutoConfiguration {
@Configuration
public static class AnnotationConfig {
private ApplicationContext applicationContext;
public AnnotationConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
// 定义 bean httpHandler
@Bean
public HttpHandler httpHandler() {
return WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
}
}
}
HttpHandlerAutoConfiguration是关于HttpHandler的自动配置类。从上面的代码不难看出,在Reactive Web应用环境中,并且容器中尚未定义HttpHandler bean的情况下,它会向容器定义一个httpHandler bean,具体的构建方法是使用WebHttpHandlerBuilder来构建,最终构建的HttpHandler实现类使用HttpWebHandlerAdapter。
接下来,我们看看WebHttpHandlerBuilder构建HttpHandler的过程。
2.2 WebHttpHandlerBuilder
使用WebHttpHandlerBuilder构建HttpHandler的第一步,是基于应用上下文创建构建器对象自身:
// WebHttpHandlerBuilder 代码片段
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
// 获取容器中名称为 webHandler, 类型为 WebHandler 的 bean , 不能为 null
// 基于此 bean 创建 builder 对象
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
// 获取容器中所有类型为 WebFilter 的 bean,可以没有,可以多个
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
builder.filters(filters -> filters.addAll(webFilters));
// 获取容器中所有类型为 WebExceptionHandler 的 bean,可以没有,可以多个
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
// 获取容器中名称为 webSessionManager, 类型为 WebSessionManager 的 bean , 可以为 null
try {
builder.sessionManager(
context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
// 获取容器中名称为 serverCodecConfigurer, 类型为 ServerCodecConfigurer 的 bean , 可以为 null
try {
builder.codecConfigurer(
context.getBean(SERVER_CODEC_CONFIGURER_BEAN_NAME, ServerCodecConfigurer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
// 获取容器中名称为 localeContextResolver, 类型为 LocaleContextResolver 的 bean , 可以为 null
try {
builder.localeContextResolver(
context.getBean(LOCALE_CONTEXT_RESOLVER_BEAN_NAME, LocaleContextResolver.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
// 不可思议的事情发生了 , 这里为什么要重复上面的逻辑 ? 给我一个不是 bug 的理由 ?
try {
builder.localeContextResolver(
context.getBean(LOCALE_CONTEXT_RESOLVER_BEAN_NAME, LocaleContextResolver.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
// 获取容器中名称为 localeContextResolver, 类型为 ForwardedHeaderTransformer 的 bean , 可以为 null
try {
builder.forwardedHeaderTransformer(
context.getBean(FORWARDED_HEADER_TRANSFORMER_BEAN_NAME, ForwardedHeaderTransformer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
return builder;
}
如上静态方法applicationContext其实是一个工厂方法,它从应用上下文中获取创建WebHttpHandlerBuilder所需要的各种工作组件bean,然后基于此创建了WebHttpHandlerBuilder对象。接下来才是使用WebHttpHandlerBuilder构建HttpHandler对象,如下所示 :
/**
* Build the {@link HttpHandler}.
*/
public HttpHandler build() {
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
// 创建 HttpWebHandlerAdapter 对象
// 一个 HttpWebHandlerAdapter 将一个 WebHandler 适配为一个 HttpHandler
HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
if (this.sessionManager != null) {
adapted.setSessionManager(this.sessionManager);
}
if (this.codecConfigurer != null) {
adapted.setCodecConfigurer(this.codecConfigurer);
}
if (this.localeContextResolver != null) {
adapted.setLocaleContextResolver(this.localeContextResolver);
}
if (this.forwardedHeaderTransformer != null) {
adapted.setForwardedHeaderTransformer(this.forwardedHeaderTransformer);
}
if (this.applicationContext != null) {
adapted.setApplicationContext(this.applicationContext);
}
adapted.afterPropertiesSet();
return adapted;
}
到此为止,我们可以看到,Reactive Web服务器的启动主要就是以下三个要点 :
- 启动
NettyWebServer,实际上是一个HttpServer; - 启动一个前台线程阻塞等待
NettyWebServer的结束; - 所启动的
NettyWebServer用于处理请求的HttpHandler来自自动配置HttpHandlerAutoConfiguration。
在Reactive Web服务器启动之后,应用就处于可以对外提供服务的状态了。不过,非常重要的一点,HttpHandler构建过程中从容器获取了各种这样的工作组件,那这些工作组件分别负责什么角色 ?又是来自哪里呢 ?
下一篇文章,我们来解答这些问题:自动配置机制WebFluxAutoConfiguration。
本文深入剖析ReactiveWeb服务器的启动过程,包括NettyWebServer的启动、启动线程的阻塞等待以及HttpHandler的自动配置机制。揭示了NettyWebServer如何处理请求,以及HttpHandler组件的构建细节。
830

被折叠的 条评论
为什么被折叠?



