Tomcat 是如何启动的

run 方法
总结下步骤为 > 1. 配置属性 > 2. 获取监听器,发布应用开始启动事件 > 3. 初始化输入参数 > 4. 配置环境,输出 banner > 5. 创建上下文 > 6. 预处理上下文 > 7. 刷新上下文 > 8. 再刷新上下文 > 9. 发布应用已经启动事件 > 10. 发布应用启动完成事件

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. ConfigurableApplicationContext context = null;
  5. Collection<springbootexceptionreporter> exceptionReporters = new ArrayList<>();
  6. //设置系统属性『java.awt.headless』,为true则启用headless模式支持
  7. configureHeadlessProperty();
  8. //通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,
  9. //找到声明的所有SpringApplicationRunListener的实现类并将其实例化,
  10. //之后逐个调用其started()方法,广播SpringBoot要开始执行了
  11. SpringApplicationRunListeners listeners = getRunListeners(args);
  12. //发布应用开始启动事件
  13. listeners.starting();
  14. try {
  15. //初始化参数
  16. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  17. //创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),
  18. //并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕。
  19. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  20. configureIgnoreBeanInfo(environment);
  21. //打印banner
  22. Banner printedBanner = printBanner(environment);
  23. //创建应用上下文
  24. ==============
  25. context = createApplicationContext();
  26. ==============
  27. //通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,获取并实例化异常分析器
  28. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
  29. new Class[] { ConfigurableApplicationContext.class }, context);
  30. //为ApplicationContext加载environment,之后逐个执行ApplicationContextInitializer的initialize()方法来进一步封装ApplicationContext,
  31. //并调用所有的SpringApplicationRunListener的contextPrepared()方法,【EventPublishingRunListener只提供了一个空的contextPrepared()方法】,
  32. //之后初始化IoC容器,并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,
  33. //这里就包括通过**@EnableAutoConfiguration**导入的各种自动配置类。
  34. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  35. //刷新上下文
  36. ==============
  37. refreshContext(context);
  38. ==============
  39. //再一次刷新上下文,其实是空方法,可能是为了后续扩展。
  40. afterRefresh(context, applicationArguments);
  41. stopWatch.stop();
  42. if (this.logStartupInfo) {
  43. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  44. }
  45. //发布应用已经启动的事件
  46. listeners.started(context);
  47. //遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。
  48. //我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。
  49. callRunners(context, applicationArguments);
  50. } catch (Throwable ex) {
  51. handleRunFailure(context, ex, exceptionReporters, listeners);
  52. thrownew IllegalStateException(ex);
  53. }
  54. try {
  55. //应用已经启动完成的监听事件
  56. listeners.running(context);
  57. } catch (Throwable ex) {
  58. handleRunFailure(context, ex, exceptionReporters, null);
  59. thrownew IllegalStateException(ex);
  60. }
  61. return context;
  62. }

其实上面这段代码,如果只要分析 tomcat 内容的话,只需要关注两个内容即可,上下文是如何创建的,上下文是如何刷新的,分别对应的方法就是 createApplicationContext() 和 refreshContext(context),接下来我们来看看这两个方法做了什么。

创建上下文

这里就是根据我们的 webApplicationType 来判断创建哪种类型的 Servlet,代码中分别对应着 Web 类型(SERVLET),响应式 Web 类型(REACTIVE),非 Web 类型(default),我们建立的是 Web 类型,所以肯定实例化 DEFAULT_SERVLET_WEB_CONTEXT_CLASS 指定的类,也就是 AnnotationConfigServletWebServerApplicationContext 类

刷新上下文

这里还是直接传递调用本类的 refresh(context)方法,最后是强转成父类 AbstractApplicationContext 调用其 refresh()方法

  1. // 类:AbstractApplicationContext
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // Prepare this context for refreshing.
  5. prepareRefresh();
  6. // Tell the subclass to refresh the internal bean factory.
  7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  8. // Prepare the bean factory for use in this context.
  9. prepareBeanFactory(beanFactory);
  10. try {
  11. // Allows post-processing of the bean factory in context subclasses.
  12. postProcessBeanFactory(beanFactory);
  13. // Invoke factory processors registered as beans in the context.
  14. invokeBeanFactoryPostProcessors(beanFactory);
  15. // Register bean processors that intercept bean creation.
  16. registerBeanPostProcessors(beanFactory);
  17. // Initialize message source for this context.
  18. initMessageSource();
  19. // Initialize event multicaster for this context.
  20. initApplicationEventMulticaster();
  21. // 在特定上下文子类中初始化其他特殊bean。这里的意思就是调用各个子类的onRefresh()
  22. ============
  23. onRefresh();
  24. ============
  25. // Check for listener beans and register them.
  26. registerListeners();
  27. // Instantiate all remaining (non-lazy-init) singletons.
  28. finishBeanFactoryInitialization(beanFactory);
  29. // Last step: publish corresponding event.
  30. finishRefresh();
  31. }
  32. catch (BeansException ex) {
  33. if (logger.isWarnEnabled()) {
  34. logger.warn("Exception encountered during context initialization - " +
  35. "cancelling refresh attempt: " + ex);
  36. }
  37. // Destroy already created singletons to avoid dangling resources.
  38. destroyBeans();
  39. // Reset 'active' flag.
  40. cancelRefresh(ex);
  41. // Propagate exception to caller.
  42. throw ex;
  43. }
  44. finally {
  45. // Reset common introspection caches in Spring's core, since we
  46. // might not ever need metadata for singleton beans anymore...
  47. resetCommonCaches();
  48. }
  49. }
  50. }

这里我们看到 onRefresh()方法是调用其子类的实现,根据我们上文的分析,我们这里的子类是 ServletWebServerApplicationContext。
到这里,其实庐山真面目已经出来了,createWebServer()就是启动 web 服务,但是还没有真正启动 Tomcat,既然 webServer 是通过 ServletWebServerFactory 工厂来获取的。
其中 Tomcat 启动为:
TomcatServletWebServerFactory.getWebServer()