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