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