Spring Boot启动原理:从main方法到内嵌Tomcat的全过程
Spring Boot的启动过程是一个精心设计的自动化流程,下面我将详细阐述从main方法开始到内嵌Tomcat启动的全过程。
1. 入口:main方法
一切始于一个简单的main方法:
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
2. SpringApplication初始化
SpringApplication.run()
方法内部会创建一个SpringApplication实例:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return new SpringApplication(primarySource).run(args);
}
2.1 构造阶段
在SpringApplication构造函数中完成以下关键操作:
- 推断应用类型:判断是Servlet应用(Spring MVC)还是Reactive应用(Spring WebFlux)
- 加载ApplicationContextInitializer:通过META-INF/spring.factories加载
- 加载ApplicationListener:同样通过spring.factories机制加载
- 推断主配置类:通过堆栈分析找到包含main方法的类
3. 运行阶段:run()方法
run()
方法是整个启动过程的核心:
public ConfigurableApplicationContext run(String... args) {// 1. 创建并启动计时器StopWatch stopWatch = new StopWatch();stopWatch.start();// 2. 初始化应用上下文和异常报告器ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();configureHeadlessProperty();// 3. 获取SpringApplicationRunListeners并启动SpringApplicationRunListeners listeners = getRunListeners(args);listeners.starting();try {// 4. 准备环境ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 5. 打印BannerBanner printedBanner = printBanner(environment);// 6. 创建应用上下文context = createApplicationContext();// 7. 准备应用上下文prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 8. 刷新应用上下文(关键步骤)refreshContext(context);// 9. 刷新后处理afterRefresh(context, applicationArguments);// 10. 停止计时器并发布启动完成事件stopWatch.stop();if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}listeners.started(context);// 11. 执行RunnercallRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}return context;
}
4. 创建应用上下文
createApplicationContext()
方法根据应用类型创建不同的应用上下文:
- Servlet环境:创建
AnnotationConfigServletWebServerApplicationContext
- Reactive环境:创建
AnnotationConfigReactiveWebServerApplicationContext
- 普通环境:创建
AnnotationConfigApplicationContext
对于Web应用,会创建AnnotationConfigServletWebServerApplicationContext
,它继承自ServletWebServerApplicationContext
。
5. 准备应用上下文
prepareContext()
方法完成以下工作:
- 将环境绑定到上下文
- 后置处理上下文
- 应用所有初始化器
- 发布ContextPrepared事件
- 注册主配置类bean定义
- 发布ContextLoaded事件
6. 刷新应用上下文
refreshContext()
最终调用AbstractApplicationContext.refresh()
,这是Spring容器的核心刷新流程:
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 1. 准备刷新prepareRefresh();// 2. 获取新的BeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 3. 准备BeanFactoryprepareBeanFactory(beanFactory);try {// 4. 后置处理BeanFactorypostProcessBeanFactory(beanFactory);// 5. 调用BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// 6. 注册BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 7. 初始化MessageSourceinitMessageSource();// 8. 初始化事件广播器initApplicationEventMulticaster();// 9. 初始化特殊bean(由子类实现)onRefresh();// 10. 注册监听器registerListeners();// 11. 初始化所有非懒加载单例finishBeanFactoryInitialization(beanFactory);// 12. 完成刷新finishRefresh();}catch (BeansException ex) {// 处理异常...}}
}
7. 内嵌Tomcat启动的关键:onRefresh()
对于Servlet Web应用,ServletWebServerApplicationContext
重写了onRefresh()
方法:
protected void onRefresh() {super.onRefresh();try {createWebServer();}catch (Throwable ex) {throw new ApplicationContextException("Unable to start web server", ex);}
}
createWebServer()
是内嵌服务器启动的关键:
private void createWebServer() {WebServer webServer = this.webServer;ServletContext servletContext = getServletContext();if (webServer == null && servletContext == null) {// 1. 获取WebServer工厂(Tomcat, Jetty或Undertow)ServletWebServerFactory factory = getWebServerFactory();// 2. 创建WebServerthis.webServer = factory.getWebServer(getSelfInitializer());}else if (servletContext != null) {try {getSelfInitializer().onStartup(servletContext);}catch (ServletException ex) {throw new ApplicationContextException("Cannot initialize servlet context", ex);}}initPropertySources();
}
8. Tomcat服务器创建过程
以Tomcat为例,TomcatServletWebServerFactory.getWebServer()
方法:
public WebServer getWebServer(ServletContextInitializer... initializers) {// 1. 创建Tomcat实例Tomcat tomcat = new Tomcat();// 2. 配置基础目录File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");tomcat.setBaseDir(baseDir.getAbsolutePath());// 3. 配置连接器Connector connector = new Connector(this.protocol);connector.setThrowOnFailure(true);tomcat.getService().addConnector(connector);customizeConnector(connector);tomcat.setConnector(connector);// 4. 配置Hosttomcat.getHost().setAutoDeploy(false);configureEngine(tomcat.getEngine());// 5. 准备上下文prepareContext(tomcat.getHost(), initializers);// 6. 创建TomcatWebServer并启动return getTomcatWebServer(tomcat);
}
9. 启动Tomcat
在TomcatWebServer
构造函数中完成Tomcat的启动:
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {this.tomcat = tomcat;this.autoStart = autoStart;initialize();
}private void initialize() throws WebServerException {// 启动Tomcatthis.tomcat.start();// 启动一个守护线程来等待停止命令startDaemonAwaitThread();
}
10. 自动配置的关键
整个过程中,自动配置是通过@SpringBootApplication
注解中的@EnableAutoConfiguration
实现的:
- 在
invokeBeanFactoryPostProcessors()
阶段会处理自动配置 AutoConfigurationImportSelector
会加载META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
文件中的配置类- 对于Tomcat,会加载
ServletWebServerFactoryAutoConfiguration
- 这个配置类通过
@Import
引入了EmbeddedTomcat
等配置
总结流程
- 启动main方法
- 创建SpringApplication实例
- 运行run()方法
- 准备环境
- 创建应用上下文(AnnotationConfigServletWebServerApplicationContext)
- 准备上下文(注册配置类等)
- 刷新上下文(核心)
- 调用onRefresh()
- 创建内嵌Web服务器(Tomcat)
- 启动Tomcat
- 发布启动完成事件
- 执行Runner