SpringBoot源码分析-Tomcat-启动流程

蓝咒 提交于 2019-12-27 13:19:12

【推荐】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

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());
            }
        }
    }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!