美文网首页
Spring Boot:Tomcat启动过程

Spring Boot:Tomcat启动过程

作者: ryancao_b9b9 | 来源:发表于2020-03-28 19:02 被阅读0次

一、软件版本

Spring Boot:2.0.1.RELEASE
Tomcat:8.5.16

二、Tomcat启动UML解析


Tomcat启动解析.png

三、Tomcat启动代码解析

1、SpringApplication内部流程

(1)public ConfigurableApplicationContext run(String... args) {
    ...
   refreshContext(context);//刷新上下文
    ...
 }

(2)private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }

(3)protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

2、AbstractApplicationContext内部流程

(4)public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
              ...
            } finally {
                this.resetCommonCaches();
            }

        }
    }

(5)protected void onRefresh() throws BeansException {
    }

3、ServletWebServerApplicationContex内部流程

        @Override
    (5)protected void onRefresh() {
        super.onRefresh();
        try {
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start web server", ex);
        }
    }

        (6)private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = getWebServerFactory();
            this.webServer = factory.getWebServer(getSelfInitializer());
        }
        else if (servletContext != null) {
            try {
                getSelfInitializer().onStartup(servletContext);
            }
            catch (ServletException ex) {
                throw new ApplicationContextException("Cannot initialize servlet context",
                        ex);
            }
        }
        initPropertySources();
    }

      //启动服务器
      (9)private WebServer startWebServer() {
        WebServer webServer = this.webServer;
        if (webServer != null) {
            webServer.start();
        }
        return webServer;
    }

4、TomcatServletWebServerFactory内部流程

  @Override
  (7)public WebServer getWebServer(ServletContextInitializer... initializers) {
        Tomcat tomcat = new Tomcat();
        File baseDir = (this.baseDirectory != null ? this.baseDirectory
                : createTempDir("tomcat"));
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        tomcat.getService().addConnector(connector);
        customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        configureEngine(tomcat.getEngine());
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        prepareContext(tomcat.getHost(), initializers);
                //启动Tomcat
        (8)return getTomcatWebServer(tomcat);
    }

四、补充说明
1、Tomcat相关的配置类
Spring通过ServletWebServerFactoryCustomizer,TomcatServletWebServerFactoryCustomizer, TomcatWebServerFactoryCustomizer三个配置类对tomcat完成配置。

ServletWebServerFactoryConfiguration

@Configuration
class ServletWebServerFactoryConfiguration {

    @Configuration
    @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
    @ConditionalOnMissingBean(value = ServletWebServerFactory.class,
            search = SearchStrategy.CURRENT)
    public static class EmbeddedTomcat {

         //定义TomcatServletWebServerFactory的bean definition
        @Bean
        public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
            return new TomcatServletWebServerFactory();
        }

    }
  ...
  ...
  ...
}

ServletWebServerFactoryAutoConfiguration

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
        ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

    // 主要配置通用的 servlet 的信息,包含端口、上下文路径、应用名、Session配置、Servlet 携带的初始变量等等
    @Bean
    public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
            ServerProperties serverProperties) {
        return new ServletWebServerFactoryCustomizer(serverProperties);
    }

    //配置tomcat的额外信息,redirectContextRoot(是否在请求根上下文时转发,true则转发路径为/demoWeb/)和useRelativeRedirects(是否使用相对路径)等路径跳转问题处理
    @Bean
    @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
    public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
            ServerProperties serverProperties) {
        return new TomcatServletWebServerFactoryCustomizer(serverProperties);
    }
  ...
  ...
  ...
}

EmbeddedWebServerFactoryCustomizerAutoConfiguration

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    /**
     * Nested configuration if Tomcat is being used.
     */
    @Configuration
    @ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
    public static class TomcatWebServerFactoryCustomizerConfiguration {

        //配置tomcat的主要信息,包含 remoteIpValue、connector(最大/最小可接收线程、最大可接收头部大小等等)、uriEncoding、connectionTimeout、maxConnection等属性
        @Bean
        public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
                Environment environment, ServerProperties serverProperties) {
            return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
        }

    }
  ...
  ...
  ...
}

2、ServletContextInitializer说明
在ServletWebServerApplicationContext中有一段getWebServer(getSelfInitializer())代码,
getWebServer的参数为函数式接口,getSelfInitializer()返回的函数内容为:selfInitialize,作用:注册所有的 servlet 组件 (包括 Servlet,Filter,Listener),源码如下:

/**
     * Returns the {@link ServletContextInitializer} that will be used to complete the
     * setup of this {@link WebApplicationContext}.
     * @return the self initializer
     * @see #prepareWebApplicationContext(ServletContext)
     */
    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
        return this::selfInitialize;
    }

    private void selfInitialize(ServletContext servletContext) throws ServletException {
        prepareWebApplicationContext(servletContext);
        registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(),
                servletContext);
        // 这一步是获取所有的 servlet 组件
        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            beans.onStartup(servletContext);
        }
    }

ServletContextInitializer是一个函数式接口,源码如下:

@FunctionalInterface
public interface ServletContextInitializer {

    /**
     * Configure the given {@link ServletContext} with any servlets, filters, listeners
     * context-params and attributes necessary for initialization.
     * @param servletContext the {@code ServletContext} to initialize
     * @throws ServletException if any call against the given {@code ServletContext}
     * throws a {@code ServletException}
     */
    void onStartup(ServletContext servletContext) throws ServletException;
}

五、参考文章
1、https://www.jianshu.com/p/6d6d2e47bf41
2、https://www.jianshu.com/p/fa44510230a2

相关文章

网友评论

      本文标题:Spring Boot:Tomcat启动过程

      本文链接:https://www.haomeiwen.com/subject/dumsuhtx.html