前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring NettyWebServer 启动运行机制

Spring NettyWebServer 启动运行机制

原创
作者头像
安宁
修改2020-07-15 11:23:46
2.6K0
修改2020-07-15 11:23:46
举报

本文主要介绍 Spring 框架中 NettyWebServer的启动运行机制。

1. 版本说明

源码分析基于:

  • spring-webflux:5.2.6
  • spring-boot:2.3.0

2. 创建过程

在运行 Spring Boot Reactive 应用时,需要在应用内启动一个 WebServer,那么 WebServer 的启动过程是怎样的呢?通过以下源码:

WebServerManager

代码语言:javascript
复制
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);
    this.webServer = factory.getWebServer(this.handler);
}

可以看出:WebServer 是由 ReactiveWebServerFactoryWebServerManager 实例化时创建的。

那么 ReactiveWebServerFactory 是怎么创建的呢?通过以下源码:

ReactiveWebServerFactoryConfiguration.EmbeddedNetty

代码语言:javascript
复制
@Bean
NettyReactiveWebServerFactory nettyReactiveWebServerFactory(ReactorResourceFactory resourceFactory,
        ObjectProvider<NettyRouteProvider> routes, ObjectProvider<NettyServerCustomizer> serverCustomizers) {
    NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();
    serverFactory.setResourceFactory(resourceFactory);
    routes.orderedStream().forEach(serverFactory::addRouteProviders);
    serverFactory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
    return serverFactory;
}

可以看出:在 ReactiveWebServerFactoryConfiguration.EmbeddedNetty 中声明了 NettyReactiveWebServerFactory。那么 ReactiveWebServerFactoryConfiguration.EmbeddedNetty 是如何启用的呢?通过以下源码:

ReactiveWebServerFactoryAutoConfiguration

代码语言:javascript
复制
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ReactiveHttpInputMessage.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ReactiveWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
                ReactiveWebServerFactoryConfiguration.EmbeddedTomcat.class,
                ReactiveWebServerFactoryConfiguration.EmbeddedJetty.class,
                ReactiveWebServerFactoryConfiguration.EmbeddedUndertow.class,
                ReactiveWebServerFactoryConfiguration.EmbeddedNetty.class })
public class ReactiveWebServerFactoryAutoConfiguration {...}

可以看出:在 ReactiveWebServerFactoryAutoConfiguration 中导入了 ReactiveWebServerFactoryConfiguration.EmbeddedNetty

那么 WebServerManager 是怎么创建的呢?通过以下源码:

ReactiveWebServerApplicationContext.createWebServer()

代码语言:javascript
复制
private void createWebServer() {
    WebServerManager serverManager = this.serverManager;
    if (serverManager == null) {
        String webServerFactoryBeanName = getWebServerFactoryBeanName();
        ReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);
        boolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();
        this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);
        getBeanFactory().registerSingleton("webServerGracefulShutdown",
                new WebServerGracefulShutdownLifecycle(this.serverManager));
        getBeanFactory().registerSingleton("webServerStartStop",
                new WebServerStartStopLifecycle(this.serverManager));
    }
    initPropertySources();
}

可以看出:WebServerManager 是在 ReactiveWebServerApplicationContext 中创建的。关于 ReactiveWebServerApplicationContext 的创建过程可以参考 SpringApplication启动时如何选择ConfigurableApplicationContext

小结:

  1. ReactiveWebServerApplicationContext.createWebServer()
  2. new WebServerManager(…​,ReactiveWebServerFactory,…​)
  3. ReactiveWebServerFactory.getWebServer(HttpHandler)

3. 启动过程

已经创建好了 WebServer,那么何时启动呢?通过以下源码:

WebServerStartStopLifecycle.start()

代码语言:javascript
复制
public void start() {
    this.weServerManager.start();
    this.running = true;
}

可以看出:在 WebServerStartStopLifecycle.start() 中调用了 WebServerManager.start(),而 WebServerManager.start() 又调用了 WebServer.start()。那么 WebServerStartStopLifecycle.start() 是何时被调用的呢?在 ReactiveWebServerApplicationContext.createWebServer 中,已经将 WebServerStartStopLifecycle 注册到了应用上下文,WebServerStartStopLifecycle 实现了 Lifecycle 接口。通过以下源码:

DefaultLifecycleProcessor.startBeans(boolean)

代码语言:javascript
复制
private void startBeans(boolean autoStartupOnly) {
    Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
    Map<Integer, LifecycleGroup> phases = new HashMap<>();
    lifecycleBeans.forEach((beanName, bean) -> {
        if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
            int phase = getPhase(bean);
            LifecycleGroup group = phases.get(phase);
            if (group == null) {
                group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
                phases.put(phase, group);
            }
            group.add(beanName, bean);
        }
    });
    if (!phases.isEmpty()) {
        List<Integer> keys = new ArrayList<>(phases.keySet());
        Collections.sort(keys);
        for (Integer key : keys) {
            phases.get(key).start();
        }
    }
}

可以看出:Lifecycle.start() 会被 DefaultLifecycleProcessor.startBeans(boolean) 调用。从应用启动到 WebServer.start(),完整的调用路径如下:

  1. SpringApplication.run
  2. SpringApplication.refresh
  3. ReactiveWebServerApplicationContext.refresh
  4. AbstractApplicationContext.finishRefresh
  5. DefaultLifecycleProcessor.onRefresh
代码语言:javascript
复制
public void onRefresh() {
    startBeans(true);
    this.running = true;
}

小结:

  1. ReactiveWebServerApplicationContext.createWebServer():注册 WebServerStartStopLifecycle
  2. DefaultLifecycleProcessor.onRefresh():触发 WebServerStartStopLifecycle.start()

4. 应用编程

现在服务已经启动了,那么服务启动之后,如何运行我们的代码呢?通过以下源码:

NettyReactiveWebServerFactory.getWebServer

代码语言:javascript
复制
public WebServer getWebServer(HttpHandler httpHandler) {
    HttpServer httpServer = createHttpServer();
    ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
    NettyWebServer webServer = new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout, getShutdown());
    webServer.setRouteProviders(this.routeProviders);
    return webServer;
}

可以看出:构造 NettyWebServer 需要传入 HttpHandler,而这个 HttpHandler 就是 NettyWebServer 处理请求的主要入口。那么 HttpHandler 是怎么被创建的呢?通过以下源码:

HttpHandlerAutoConfiguration.AnnotationConfig

代码语言:javascript
复制
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
    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 是由 WebHttpHandlerBuilder.applicationContext(ApplicationContext).build() 构建的。通过以下源码:

WebHttpHandlerBuilder.applicationContext

代码语言:javascript
复制
public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
    WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
            context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);

    List<WebFilter> webFilters = context
            .getBeanProvider(WebFilter.class)
            .orderedStream()
            .collect(Collectors.toList());
    builder.filters(filters -> filters.addAll(webFilters));
    ...
    return builder;
}

可以看出: WebHttpHandlerBuilderApplicationContext 中取出以下 Bean:

  1. WebHandler [1] — 查找 1 个名为 webHandler 的 WebHandler
  2. WebFilter [0..N] — 查找 0~n 个 WebFilter 并排序
  3. WebExceptionHandler [0..N] — 查找 0~n 个 WebExceptionHandler 并排序
  4. WebSessionManager [0..1] — 查找 1 个名为 webSessionManager 的 WebSessionManager
  5. ServerCodecConfigurer [0..1] — 查找 1 个名为 serverCodecConfigurer 的 ServerCodecConfigurer
  6. LocaleContextResolver [0..1] — 查找 1 个名为 localeContextResolver 的 LocaleContextResolver

并使用这些 Bean 构建 HttpHandler

WebHttpHandlerBuilder.build

代码语言:javascript
复制
public HttpHandler build() {

    WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
    decorated = new ExceptionHandlingWebHandler(decorated,  this.exceptionHandlers);

    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;
}

最终构建出 HttpHandler 类似以下示例:

代码语言:javascript
复制
HttpHandler httpHandler = new HttpWebHandlerAdapter(
    new ExceptionHandlingWebHandler(
        new FilteringWebHandler(
            new DispatcherHandler(...)
        , this.filters)
    ,  this.exceptionHandlers)
);

小结:

  1. NettyReactiveWebServerFactory.getWebServer(HttpHandler)
  2. WebHttpHandlerBuilder.applicationContext(ApplicationContext).build()

5. 彩蛋

查看源码过程中,发现一个 BUG,已上报到 spring-framework

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 版本说明
  • 2. 创建过程
  • 3. 启动过程
  • 4. 应用编程
  • 5. 彩蛋
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档