Spring Boot在创建Reactive类型的Web服务器时,会从bean工厂中查找HttpHandler类型的bean。在NettyReactiveWebServerFactory的实现中,会利用该bean创建ReactorHttpHandlerAdapter。这个适配器是Spring Framework中提供的类,底层的ReactoryNetty收到请求后,会调用该适配器,而该适配器又会调用设置的HttpHandler来处理请求。
在Spring Boot中的Web服务器一文中,只是讲到Spring Boot会自动往bean工厂中注册一个HttpHandler类型的bean,但没有讲到具体的创建过程是怎样的。
Spring Boot中的自动配置
@AutoConfiguration(after = { WebFluxAutoConfiguration.class })
@ConditionalOnClass({ DispatcherHandler.class, HttpHandler.class })
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnMissingBean(HttpHandler.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class HttpHandlerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
public static class AnnotationConfig {
private final ApplicationContext applicationContext;
public AnnotationConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
// 创建HTTP处理器,WebHttpHandlerBuilder属于spring-web模块,其实这里创建的是HttpWebHandlerAdapter,该bean同时也是WebHandler
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
WebFluxProperties properties = propsProvider.getIfAvailable();
if (properties != null && StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
return new ContextPathCompositeHandler(handlersMap);
}
return httpHandler;
}
}
}
这个自动配置类中注册了HttpHandler类型的bean,是通过Spring Framework提供的类WebHttpHandlerBuilder来构建的,构建过程分为两步:
- 准备构建:从应用上下文中获取一系列的组件bean,会被用来构建HttpHandler对象。
- 执行构建;
准备构建
/** Well-known name for the target WebHandler in the bean factory. */
public static final String WEB_HANDLER_BEAN_NAME = "webHandler";
/** Well-known name for the WebSessionManager in the bean factory. */
public static final String WEB_SESSION_MANAGER_BEAN_NAME = "webSessionManager";
/** Well-known name for the ServerCodecConfigurer in the bean factory. */
public static final String SERVER_CODEC_CONFIGURER_BEAN_NAME = "serverCodecConfigurer";
/** Well-known name for the LocaleContextResolver in the bean factory. */
public static final String LOCALE_CONTEXT_RESOLVER_BEAN_NAME = "localeContextResolver";
/** Well-known name for the ForwardedHeaderTransformer in the bean factory. */
public static final String FORWARDED_HEADER_TRANSFORMER_BEAN_NAME = "forwardedHeaderTransformer";
/*
* 在SpringBoot中,HttpHandlerAutoConfiguration类有一个静态内部配置类,
* 该配置类向容器中注入了一个httpHandler,在该方法中调用了此方法以及下面的build方法。
*/
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
/*
* 创建builder对象,
* 获取容器中名为webHandler且类型是WebHandler的bean作为构造器参数,这个bean就是核心组件DispatcherHandler
* 该bean是在WebFluxConfigurationSupport类中注入容器的。
*
* 在SpringBoot中,WebFluxAutoConfiguration中会有一个叫作EnableWebFluxConfiguration的静态内部配置类,
* 该配置类继承了DelegatingWebFluxConfiguration,而该类又继承了WebFluxConfigurationSupport类。
*/
WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
// 这里获取到的是DispatcherHandler
context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class),
context);
// 从应用上下文中获取WebFilter
List<WebFilter> webFilters = context
.getBeanProvider(WebFilter.class)
.orderedStream()
.collect(Collectors.toList());
// 将过滤器添加到builder内部的filters属性中
builder.filters(filters -> filters.addAll(webFilters));
// 获取异常处理器
List<WebExceptionHandler> exceptionHandlers = context
.getBeanProvider(WebExceptionHandler.class)
.orderedStream()
.collect(Collectors.toList());
// 设置异常处理器
builder.exceptionHandlers(handlers -> handlers.addAll(exceptionHandlers));
// 获取httpHandler装饰器,并设置给builder
context.getBeanProvider(HttpHandlerDecoratorFactory.class)
.orderedStream()
.forEach(builder::httpHandlerDecorator);
try {
// 设置session管理器
builder.sessionManager(
context.getBean(WEB_SESSION_MANAGER_BEAN_NAME, WebSessionManager.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
// 设置编码配置器
builder.codecConfigurer(
context.getBean(SERVER_CODEC_CONFIGURER_BEAN_NAME, ServerCodecConfigurer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
// 设置本地上下文解析器
builder.localeContextResolver(
context.getBean(LOCALE_CONTEXT_RESOLVER_BEAN_NAME, LocaleContextResolver.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
try {
//
builder.forwardedHeaderTransformer(
context.getBean(FORWARDED_HEADER_TRANSFORMER_BEAN_NAME, ForwardedHeaderTransformer.class));
}
catch (NoSuchBeanDefinitionException ex) {
// Fall back on default
}
return builder;
}
该方法较长,具体操作可以总结如下:
- 创建builder对象,会从应用上下文中获取web处理器;
- 获取并设置WebFilter;
- 获取并设置异常处理器;
- 获取并设置httpHandler装饰器;
- 设置session管理器;
- 设置编码配置器;
- 设置本地上下文解析器;
本质上就是在从应用上下文中获取bean,然后设置到builder的属性中。
获取Web处理器
这里在获取WebHandler类型且名称为“webHandler”的bean,那是哪里注册了该bean的?在Spring Boot中的HttpHandlerAutoConfiguration类中会引入另外一个自动配置类:WebFluxAutoConfiguration。在这个类中又有一个内部类叫作EnableWebFluxConfiguration,它是WebFluxConfigurationSupport类的子类。WebFluxConfigurationSupport中会注册很多组件bean,其中就包括WebHandler类型的bean。
/*
* 注册WebFlux的核心组件:DispatcherHandler,bean的名称为webHandler
* bean的名称正如方法名:webHandler,
* 在WebHttpHandlerBuilder中会被获取,使用的是常量属性WEB_HANDLER_BEAN_NAME,该常量的值就是webHandler。
*/
@Bean
public DispatcherHandler webHandler() {
return new DispatcherHandler();
}
DispatcherHandler是WebFlux中的请求处理器,可以理解为WebMvc中的DispatcherServlet。
执行构建
/*
* 在SpringBoot中,HttpHandlerAutoConfiguration类有一个静态内部配置类,
* 该配置类向容器中注入了一个httpHandler,在该方法中调用了此方法以及上面的applicationContext方法。
*/
public HttpHandler build() {
/*
* 采用装饰器模式封装handler和filter,这两个属性是在上面的applicationContext方法中被设置的。
* 这里的webHandler就是核心组件DispatcherHandler
* 内部会调用默认的过滤器链
*/
WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
// 再封装异常处理器
decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
// 创建适配器,并设置一些属性,由此可见adapter里面的delegate保存的是ExceptionHandlingWebHandler实例
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 (this.httpHandlerDecorator != null ? this.httpHandlerDecorator.apply(adapted) : adapted);
}
该方法的操作可以总结如下:
- 创建过滤web处理器,封装了web处理器和过滤器;
- 创建异常web处理器,封装过滤处理器和异常处理器;
- 创建处理器适配器,是HttpHandler的实现类,会被作为结果返回;
- 设置一系列其他属性;
在该方法中,大量使用了装饰器模式。最后返回给Spring Boot的是HttpWebHandlerAdapter类型的对象。
HttpHandler和WebHanlder都是Spring Framework提供的两个接口。但前者在org.springframework.http.server.reactive包下,用于WebFlux中专门处理HTTP请求;后者在org.springframework.web.server包下,处理web请求,不一定是HTTP协议的请求。
DelayedInitializationHttpHandler
Spring Boot中的NettyWebServerFactory中创建ReactorHttpHandlerAdapter类型的对象时,设置的httpHandler并不是上面创建的HttpWebHandlerAdapter,而是DelayedInitializationHttpHandler。 在Spring Boot中的WebServerManager中会对获取到的HttpHandler进行封装,以提供延迟初始化的功能。
WebServerManager(ReactiveWebServerApplicationContext applicationContext, ReactiveWebServerFactory factory,
Supplier<HttpHandler> handlerSupplier, boolean lazyInit) {
this.applicationContext = applicationContext;
Assert.notNull(factory, "Factory must not be null");
this.handler = new DelayedInitializationHttpHandler(handlerSupplier, lazyInit);
// 创建WebServer
this.webServer = factory.getWebServer(this.handler);
}
void start() {
// 初始化请求处理器(特殊的请求处理器,其实是适配器)
this.handler.initializeHandler();
// 启动WebServer
this.webServer.start();
this.applicationContext
.publishEvent(new ReactiveWebServerInitializedEvent(this.webServer, this.applicationContext));
}
会将handlerSupplier封装到DelayedInitializationHttpHandler对象中。
static final class DelayedInitializationHttpHandler implements HttpHandler {
private final Supplier<HttpHandler> handlerSupplier;
private final boolean lazyInit;
private volatile HttpHandler delegate = this::handleUninitialized;
private DelayedInitializationHttpHandler(Supplier<HttpHandler> handlerSupplier, boolean lazyInit) {
this.handlerSupplier = handlerSupplier;
this.lazyInit = lazyInit;
}
private Mono<Void> handleUninitialized(ServerHttpRequest request, ServerHttpResponse response) {
throw new IllegalStateException("The HttpHandler has not yet been initialized");
}
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
return this.delegate.handle(request, response);
}
/*
* 这个方法是什么时候被调用的?
*/
void initializeHandler() {
/*
* 实现是否要延迟初始化请求处理器的逻辑。
*/
this.delegate = this.lazyInit ? new LazyHttpHandler(this.handlerSupplier) :
// 获取HttpHandler,获取的类型是HttpWebHandlerAdapter
this.handlerSupplier.get();
}
HttpHandler getHandler() {
return this.delegate;
}
}
private static final class LazyHttpHandler implements HttpHandler {
private final Mono<HttpHandler> delegate;
private LazyHttpHandler(Supplier<HttpHandler> handlerSupplier) {
// 保存supplier对象,先不获取委托对象
this.delegate = Mono.fromSupplier(handlerSupplier);
}
// 只有第一次调用该方法时才会调用supplier来创建`HttpHandler`
@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
// 调用委托对象的handle方法
return this.delegate.flatMap((handler) -> handler.handle(request, response));
}
}
如果是要延迟初始化,则会创建LazyHttpHandler,在它的handle方法第一次被调用时,才创建HttpHandler,从而实现延迟初始化的目的。
那这个是否延迟初始化是哪里控制的呢?这就要回到ReactiveWebServerApplicationContext中的createWebServer方法了。
private void createWebServer() {
WebServerManager serverManager = this.serverManager;
if (serverManager == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
// 获取WebServer工厂的名称
String webServerFactoryBeanName = getWebServerFactoryBeanName();
// 从容器中获取WebServer工厂实例
ReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);
createWebServer.tag("factory", webServerFactory.getClass().toString());
// 获取是否延迟初始化,对于NettyReactiveWebServerFactory来说是false
boolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();
// 创建WebServerManager对象并传入WebServer工厂,内部会创建WebServer
this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.serverManager.getWebServer()));
getBeanFactory().registerSingleton("webServerStartStop",
/*
* 该bean是一个SmartLifecycle类型实例
* (AbstractApplicationContext#refresh方法的finishRefresh阶段会处理),
* 负责WebServer的启动和关闭
*/
new WebServerStartStopLifecycle(this.serverManager));
createWebServer.end();
}
initPropertySources();
}
这里是通过web服务器工厂bean是否延迟初始化来决定的,常用的Netty服务器工厂bean是没有设置延迟初始化的。
在Spring中,可以使用@Lazy注解来配置bean的延迟初始化。