SpringBoot内置源码解析WebServer初始化过程

WebServer 初始化过程在上一节中 Spring Boot 初始化了 WebServer 对应的工厂类 。 同时 , 我们也知道对应 Web容器的WebServer实现类有:TomcatWebServer、JettyWebServer和UndertowWebServer 。
这节重点讲解这些 WebServer 是如何被初始化 , 又如何启动的 。
WebServer 接口的源代码如下 。
public interface WebServer {void start() throws WebServerException;void stop() throws WebServerException;int getPort();}接口定义了 3 个方法: start 方 法为启动容器 , stop 方 法为停止容器,getPort 方法为获得容器端口 。
SpringBoot内置源码解析WebServer初始化过程文章插图
现在以 Tomcat 的启动为例来说明整个内置容器的加载与启动 。 在上节中 , 工厂类已经被自动配置初始化 。 那么 , 在什么地方用到它们的呢?这要回到最初 Spring Boot 启动的过程中 。
还记得 SpringApplication 的 run 方法中有一个调用初始化容器的方法 refreshContext 吗?
我们就从这个方法开始追踪 。
public ConfigurableApplicationContext run(String... args) {try {//初始化容器refreshContext(context);} catch (Throwable ex) {}在 run 方法中调用了 refreshContext 方法 , refreshContext 方法中又调用了refresh 方法 。
private void refreshContext(ConfigurableApplicationContext context) {//调用 refresh 方法refresh(context);refresh 方法的代码如下 。 protected void refresh(ApplicationContext applicationContext) {Assert. isInstanceOf(AbstractApplicat ionContext. class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}通过 refresh 方法我们能看到什么呢?对的 , 就是 AbstractApplicationContext 这个抽象类 , 该类的实例化对象在调用 refreshContext 方法之前 , 已经通过 createApplicationContext 方法进行实例化了 。 createApplicationContext 方法的源代码如下 。
protected ConfigurableApplicat ionContext createApplicationContext() {//首先获取容器的类变量Class contextClass = this . applicat ionContextClass;/如果为 null,则根据 web 应用类型按照默认类进行创建if (contextClass == null) {trywitch (this . webApplicat ionType) {contextClass = Class . forName(DEFAULT_ _SERVLET _WEB_ _CONTEXT_ CLASS);break;case REACTIVE:contextClass = Class . forName (DEFAULT_ REACTIVE_ WEB_ CONTEXT_ CLASS);break;default:contextClass = Class . forName (DEFAULT CONTEXT. CLASS);}catch (ClassNotFoundException ex) {如果存在对应的 Class 配置 , 则通过 Spring 提 供的 BeanUtils 来进行实例化 return(ConfigurableApplicationContext) BeanUtils. instantiateClass(contextClass);}}}ServletWeb 项目默认会实例化 DEFAULT_ _SERVLET_ WEB_ _CONTEXT _CLASS 常量指定的 org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext 类 。
在 refresh 方法中调用的 AbstractApplicationContext 的 refresh 方法就是这个常量配置的类的 refresh 方法但 AnnotationConfigServletWebServerApplicationContext 方法内并没有该refresh 方法 , 该方法定义在它的父类 ServletWebServerApplicationContext 中 。
@Overridepublic final void refresh() throws BeansException, IllegalStateExceptiontry {super . refresh();} catch (RuntimeException ex) {stopAndReleaseWebServer();throw ex;}}ServletWebServerApplicationContext 的 refresh 方 法 仅 调 用 了 父 类AbstractApplication-Context 中的 refresh 方法 。 AbstractApplicationContext 中的 refresh方法的代码如下 。
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this . startupShutdownMonitor)try {...onRefresh();}catch (BeansException ex) {}忽略掉 refresh 方法中的其他方法 , 我们重点了解下其调用的 onRefresh 方法 。
protected void onRefresh() throws BeansException {//为子类提供 , 默认不做任何操作我们发现这个 onRefresh 方法默认是空的 , 待其子类来实现 。 也就是说 , 该方法真正的实现又回到了它的子类 ServletWebServerApplicationContext 中 。 @Overrideprotected void onRefresh() {super . onRefresh();try {createWebServer();} catch (Throwable ex){throw new ApplicationContextException("Unable to start web server", ex);}经过一路的代码跟踪 , 终于回到重点方法: createWebServer 方法 。
private void createWebServer() {WebServer webServer = this . webServer;ServletContext servletContext = getServletContext();if (webServer == null this . webServer = factory . getWebServer(getSelfInitializer());} else if (servletContext != null) {initPropertySources();}}在 ServletWebServerApplicationContext 的 createWebServer 方 法 中,初 始 化 时 默 认web-Server 和 servletContext 都为 null,因此直接进入第一个 if 判断中的业务逻辑 。 看一下get-WebServerFactory 都做 了些什么 。