【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
上一篇: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
实例化相关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()); } } }
来源:oschina
链接:https://my.oschina.net/u/3049601/blog/3148106