天天看点

Spring容器刷新—09—onRefresh

作者:当年三岁半
Spring容器刷新—09—onRefresh

这次的内容是上图中的第09步。

前言

先来看看前面几篇文章都做了什么:

`01-prepareRefresh()`: `earlyApplicationListeners`、`applicationListeners` 、`initPropertySources()`、`validateRequiredProperties`
`02-obtainFreshBeanFactory()`: `refreshBeanFactory`
`03-prepareBeanFactory()`: `ignoreDependencyInterface`、`setBeanExpressionResolver`、`registerResolvableDependency`、`Environment`
`04-postProcessBeanFactory()`: 具体实现类的特殊逻辑(`Servlet` 等)
`05-invokeBeanFactoryPostProcessors()`: 可能发生的对 `BeanFactory/BeanDefinitionRegistry` 的修改操作
`06-registerBeanPostProcessors()`: 所有的 `BeanPostProcessor` 已经被实例化并且注册到了 `BeanFactory` 中
`07-initMessageSource()`: `MessageSource` 已经就绪了,可以支持国际化(`I18N`)资源处理了
`08-initApplicationEventMulticaster()`: 多播器 `applicationEventMulticaster` 已经就绪了           

目前为止,ApplicationContext 已经初始化的差不多了。

但是ApplicationContext 的实现类实在是太多了,在创建剩下的单例 Bean 之前,还给子类留了一个扩展方法: onRefresh()。

ApplicationContext 的不同实现类可以针对不同环境做一些不同的事情。

最常见的就是:web 环境下可以在这一步去创建 webServer (比如 Netty/Tomcat) 了。

ApplicationContext 的实现类非常之多,还是以下面三种比较典型的场景为例,看看不同环境下的 onRefresh() 做了些什么事。

Spring容器刷新—09—onRefresh
  • XmlWebApplicationContext: 传统的 spring 和 Tomcat 等容器整合的方式,默认使用的 ApplicationContext 实现类
  • ReactiveWebServerApplicationContext: spring-boot 环境下,异步 的 Web 项目默认使用的 ApplicationContext 实现类
  • ServletWebServerApplicationContext: spring-boot 环境下,同步 的 Web 项目默认使用的 ApplicationContext 实现类

XmlWebApplicationContext

这里指的是传统的那种手动整合 spring 和 Tomcat 的方式,类似于下面这样的配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <context-param>
        <!-- 主要关注一下这个配置项, 如果不配置就从 spring-web.jar 的 `org.springframework.web.context.ContextLoader.ContextLoader.properties` 文件中获取 -->
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 省略其他配置 -->
    <!-- 省略其他配置 -->
    <!-- 省略其他配置 -->
</web-app>           

这种场景下,默认的 ApplicationContext 实现类是 XmlWebApplicationContext。

onRefresh 就初始化了一些和 WebUI 相关的一些组件,没有其他特殊的地方。

public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
    // ...
}

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {

    @Override
    protected void onRefresh() {
        // 初始化了一些和 WebUI 相关的一些组件
        this.themeSource = UiApplicationContextUtils.initThemeSource(this);
    }

}           

WebServer

在继续看 Web 环境下的 onRefresh() 之前,先看看一个叫做 WebServer 的抽象。就是对 Http 服务的一个抽象。接口声明如下:

public interface WebServer {
    void start() throws WebServerException;

    void stop() throws WebServerException;

    int getPort();

    default void shutDownGracefully(GracefulShutdownCallback callback) {
        callback.shutdownComplete(GracefulShutdownResult.IMMEDIATE);
    }
}           

再看看内置的实现:

Spring容器刷新—09—onRefresh

WebServerFactory

还有一个叫 WebServerFactory 的组件,看名字就知道他就是为了创建上面提到的 WebServer 的工厂类。不同环境有不同的实现类。

Spring容器刷新—09—onRefresh

其实,Web 环境下的 onRefresh() 主要就是在创建这个 WebServer 或者在创建 WebServerFactory。

ReactiveWebServerApplicationContext

spring-boot 环境下,异步 的 Web 项目:这一步主要是创建了 WebServerFactory。

public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext
        implements ConfigurableWebServerApplicationContext {

    private volatile WebServerManager serverManager;

    private String serverNamespace;

    @Override
    protected void onRefresh() {
        // AbstractApplicationContext中的空方法
        super.onRefresh();
        try {
            // 创建 WebServer (Netty服务端)
            createWebServer();
        } catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start reactive web server", ex);
        }
    }

    private void createWebServer() {
        WebServerManager serverManager = this.serverManager;
        if (serverManager == null) {
            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
            // 从容器中获取 ReactiveWebServerFactory 类型的 BeanName: 就是用来创建 WebServer 的工厂类
            String webServerFactoryBeanName = getWebServerFactoryBeanName();

            // 创建/获取 ReactiveWebServerFactory 单例,beanFactory.getBean(beanName)
            ReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);
            createWebServer.tag("factory", webServerFactory.getClass().toString());

            // 初始化 WebServer
            boolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();
            this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);

            // 注册几个回收资源的生命周期函数
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                    new WebServerGracefulShutdownLifecycle(this.serverManager.getWebServer()));
            getBeanFactory().registerSingleton("webServerStartStop",
                    new WebServerStartStopLifecycle(this.serverManager));
            createWebServer.end();
        }
        initPropertySources();
    }
}           

ServletWebServerApplicationContext

spring-boot 环境下,同步 的 Web 项目:这一步主要是创建了 WebServer。

public class ServletWebServerApplicationContext extends GenericWebApplicationContext
        implements ConfigurableWebServerApplicationContext {

    @Override
    protected void onRefresh() {
        // GenericWebApplicationContext.onRefresh
        // this.themeSource = UiApplicationContextUtils.initThemeSource(this);
        super.onRefresh();
        try {
            // 创建 WebServer 实例
            // 过程和上面提到的 ReactiveWebServerApplicationContext.createWebServer() 大同小异
            createWebServer();
        } catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }

    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
            ServletWebServerFactory factory = getWebServerFactory();
            createWebServer.tag("factory", factory.getClass().toString());
            this.webServer = factory.getWebServer(getSelfInitializer());
            createWebServer.end();
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                    new WebServerGracefulShutdownLifecycle(this.webServer));
            getBeanFactory().registerSingleton("webServerStartStop",
                    new WebServerStartStopLifecycle(this, this.webServer));
        } else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            } catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context", ex);
            }
        }
        initPropertySources();
    }
}

public class GenericWebApplicationContext extends GenericApplicationContext
        implements ConfigurableWebApplicationContext, ThemeSource {

    @Nullable
    private ThemeSource themeSource;

    @Override
    protected void onRefresh() {
        this.themeSource = UiApplicationContextUtils.initThemeSource(this);
    }
}