Tomcat 是如何启动的
run 方法
总结下步骤为 > 1. 配置属性 > 2. 获取监听器,发布应用开始启动事件 > 3. 初始化输入参数 > 4. 配置环境,输出 banner > 5. 创建上下文 > 6. 预处理上下文 > 7. 刷新上下文 > 8. 再刷新上下文 > 9. 发布应用已经启动事件 > 10. 发布应用启动完成事件
public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<springbootexceptionreporter> exceptionReporters = new ArrayList<>();//设置系统属性『java.awt.headless』,为true则启用headless模式支持configureHeadlessProperty();//通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,//找到声明的所有SpringApplicationRunListener的实现类并将其实例化,//之后逐个调用其started()方法,广播SpringBoot要开始执行了SpringApplicationRunListeners listeners = getRunListeners(args);//发布应用开始启动事件listeners.starting();try {//初始化参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile),//并遍历调用所有的SpringApplicationRunListener的environmentPrepared()方法,广播Environment准备完毕。ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//打印bannerBanner printedBanner = printBanner(environment);//创建应用上下文==============context = createApplicationContext();==============//通过*SpringFactoriesLoader*检索*META-INF/spring.factories*,获取并实例化异常分析器exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//为ApplicationContext加载environment,之后逐个执行ApplicationContextInitializer的initialize()方法来进一步封装ApplicationContext,//并调用所有的SpringApplicationRunListener的contextPrepared()方法,【EventPublishingRunListener只提供了一个空的contextPrepared()方法】,//之后初始化IoC容器,并调用SpringApplicationRunListener的contextLoaded()方法,广播ApplicationContext的IoC加载完成,//这里就包括通过**@EnableAutoConfiguration**导入的各种自动配置类。prepareContext(context, environment, listeners, applicationArguments, printedBanner);//刷新上下文==============refreshContext(context);==============//再一次刷新上下文,其实是空方法,可能是为了后续扩展。afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//发布应用已经启动的事件listeners.started(context);//遍历所有注册的ApplicationRunner和CommandLineRunner,并执行其run()方法。//我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。callRunners(context, applicationArguments);} catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);thrownew IllegalStateException(ex);}try {//应用已经启动完成的监听事件listeners.running(context);} catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);thrownew IllegalStateException(ex);}return context;}
其实上面这段代码,如果只要分析 tomcat 内容的话,只需要关注两个内容即可,上下文是如何创建的,上下文是如何刷新的,分别对应的方法就是 createApplicationContext() 和 refreshContext(context),接下来我们来看看这两个方法做了什么。
创建上下文
这里就是根据我们的 webApplicationType 来判断创建哪种类型的 Servlet,代码中分别对应着 Web 类型(SERVLET),响应式 Web 类型(REACTIVE),非 Web 类型(default),我们建立的是 Web 类型,所以肯定实例化 DEFAULT_SERVLET_WEB_CONTEXT_CLASS 指定的类,也就是 AnnotationConfigServletWebServerApplicationContext 类
刷新上下文
这里还是直接传递调用本类的 refresh(context)方法,最后是强转成父类 AbstractApplicationContext 调用其 refresh()方法
// 类:AbstractApplicationContextpublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// 在特定上下文子类中初始化其他特殊bean。这里的意思就是调用各个子类的onRefresh()============onRefresh();============// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}
这里我们看到 onRefresh()方法是调用其子类的实现,根据我们上文的分析,我们这里的子类是 ServletWebServerApplicationContext。
到这里,其实庐山真面目已经出来了,createWebServer()就是启动 web 服务,但是还没有真正启动 Tomcat,既然 webServer 是通过 ServletWebServerFactory 工厂来获取的。
其中 Tomcat 启动为:
TomcatServletWebServerFactory.getWebServer()
