这次的内容是上图中的第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() 做了些什么事。
- 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);
}
}
再看看内置的实现:
WebServerFactory
还有一个叫 WebServerFactory 的组件,看名字就知道他就是为了创建上面提到的 WebServer 的工厂类。不同环境有不同的实现类。
其实,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);
}
}