Spring Boot中HttpHandler的创建过程

Spring Boot在创建Reactive类型的Web服务器时,会从bean工厂中查找HttpHandler类型的bean。在NettyReactiveWebServerFactory的实现中,会利用该bean创建ReactorHttpHandlerAdapter。这个适配器是Spring Framework中提供的类,底层的ReactoryNetty收到请求后,会调用该适配器,而该适配器又会调用设置的HttpHandler来处理请求。


Spring Boot中的Web服务器一文中,只是讲到Spring Boot会自动往bean工厂中注册一个HttpHandler类型的bean,但没有讲到具体的创建过程是怎样的。

Spring Boot中的自动配置

v2.7.x
java
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfiguration.java
@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对象。
  • 执行构建;

准备构建

java
spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java
/** 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。

java
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java
/*
 * 注册WebFlux的核心组件:DispatcherHandler,bean的名称为webHandler
 * bean的名称正如方法名:webHandler,
 * 在WebHttpHandlerBuilder中会被获取,使用的是常量属性WEB_HANDLER_BEAN_NAME,该常量的值就是webHandler。
 */
@Bean
public DispatcherHandler webHandler() {
    return new DispatcherHandler();
}

DispatcherHandler是WebFlux中的请求处理器,可以理解为WebMvc中的DispatcherServlet

执行构建

java
spring-web/src/main/java/org/springframework/web/server/adapter/WebHttpHandlerBuilder.java
/*
 * 在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类型的对象。

HttpHandlerWebHanlder都是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进行封装,以提供延迟初始化的功能。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/WebServerManager.java
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对象中。

v2.7.x
DelayedInitializationHttpHandler
LazyHttpHandler
<
>
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/WebServerManager.java
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;
    }

}
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/WebServerManager.java
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方法了。

v2.7.x
java
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/context/ReactiveWebServerApplicationContext.java
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的延迟初始化。