SpringBoot源码分析Tomcat启动流程

编程

上一篇:SpringBoot源码分析-初始化Tomcat-ServletWebServerFactory实例化

在SpringBoot源码分析-初始化Tomcat-ServletWebServerFactory实例化讲了TomcatServletWebServerFactory的自动配置和实例化,在Springboot源码分析-启动流程-自动配置详解将了DispatcherServlet的自动配置,接下来就从头到尾看看Tomcat是如何一步步启动并将DispatcherServlet添加到ServletContext当中的

概要

使用时序图完成描述整个启动过程,整个过程大概分为几个步骤

  • Spring通过自动配置将Tomcat所需的相关类的BeanDefinition注册到容器中

  • Spring优先于其他Bean先实例化Web容器相关的类

  • 在onRefresh的时候使用TomcatServletWebServerFactory创建TomcatServer并完成Server的启动

  • 在finishRefresh的时候完成loadStartup>0的servlet启动操作,完成Tomcat所有启动操作

时序图

源码分析

自动配置相关类

请参考如下章节:

SpringBoot源码分析-初始化Tomcat-ServletWebServerFactoryAutoConfiguration

Springboot源码分析-启动流程-自动配置详解

实例化相关Bean与启动TomcatServer

从时序图中可以看到实例化相关Bean是在ServletWebServerApplicationContext中完成的,看看代码

private void createWebServer() {

WebServer webServer = this.webServer;

ServletContext servletContext = getServletContext();

if (webServer == null && servletContext == null) {

/**

* 这一步实例化了如下等20多个Bean:

* conventionErrorViewResolver,dispatcherServlet,dispatcherServletRegistration,

* errorPageCustomizer,localeCharsetMappingsCustomizer

*/

ServletWebServerFactory factory = getWebServerFactory();

/**

* 利用lambda传参数,将整个ApplicationContext全部传给你了 TomcatServer

* 这一步完成TomcatServletWebServerFactory生成TomcatWebServer,比如:

* 1.实例化Tomcat,配置Tomcat

* 2.实例化Connector,配置Connector

* 3.实例化TomcatEmbeddedContext,配置Context

* 4.将DispatcherServlet添加到Context当中

* 等等功能

*/

this.webServer = factory.getWebServer(getSelfInitializer());

          }

else if (servletContext != null) {

try {

getSelfInitializer().onStartup(servletContext);

}

catch (ServletException ex) {

throw new ApplicationContextException("Cannot initialize servlet context", ex);

}

}

//替换environment中servletContextInitParams

initPropertySources();

}

再看看getWebServer中的代码

public WebServer getWebServer(ServletContextInitializer... initializers) {

//实例化一个Tomcat

Tomcat tomcat = new Tomcat();

File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");

//设置Tomcat的工作临时目录

tomcat.setBaseDir(baseDir.getAbsolutePath());

//默认使用Http11NioProtocal实例化Connector

Connector connector = new Connector(this.protocol);

//给Service添加Connector

tomcat.getService().addConnector(connector);

/**

* 使用自定义的配置加强或者优化Connector

*/

customizeConnector(connector);

tomcat.setConnector(connector);

//关闭热部署

tomcat.getHost().setAutoDeploy(false);

/**

* 配置Engine:给Engine添加Valve

*/

configureEngine(tomcat.getEngine());

//添加自定义Connector,其实TomcatWebServerFactoryCustomizer并没有提供扩展点来添加Connector,但是可以向上继续追溯,可以自己添加一个Customizer

for (Connector additionalConnector : this.additionalTomcatConnectors) {

tomcat.getService().addConnector(additionalConnector);

}

prepareContext(tomcat.getHost(), initializers);

/**

* 实例化TomcatWebServer时会将DispatcherServlet以及一些Filter添加到Tomcat中

*/

return getTomcatWebServer(tomcat);

}

完成最后的启动

在finishRefresh的时候完成loadStartup>0的servlet启动操作,完成Tomcat所有启动操作

ServletWebServerApplicationContext#finishRefresh

protected void finishRefresh() {

super.finishRefresh();

/**

* 启动在Tomcat启动时就要完成启动的Servlet,检查Connector是否都启动完成,打印最终启动完成日志

*/

WebServer webServer = startWebServer();

if (webServer != null) {

publishEvent(new ServletWebServerInitializedEvent(webServer, this));

}

}

ServletWebServerApplicationContext#startWebServer

private WebServer startWebServer() {

WebServer webServer = this.webServer;

if (webServer != null) {

/**

* 完成最后的启动操作:将loadStartUp>0的Servlet启动起来

*/

webServer.start();

}

return webServer;

}

TomcatWebServer#start

public void start() throws WebServerException {

synchronized (this.monitor) {

if (this.started) {

return;

}

try {

//将早前移除的connector与Service绑定

addPreviouslyRemovedConnectors();

Connector connector = this.tomcat.getConnector();

if (connector != null && this.autoStart) {

//启动那些在Tomcat启动时就需要启动Servlet

performDeferredLoadOnStartup();

}

//检查Connector是否都启动了

checkThatConnectorsHaveStarted();

this.started = true;

//打印最终启动完成的日志

logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path ""

+ getContextPath() + """);

}

catch (ConnectorStartFailedException ex) {

stopSilently();

throw ex;

}

catch (Exception ex) {

throw new WebServerException("Unable to start embedded Tomcat server", ex);

}

finally {

Context context = findContext();

ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());

}

}

}

以上是 SpringBoot源码分析Tomcat启动流程 的全部内容, 来源链接: utcz.com/z/512113.html

回到顶部