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实例:
- 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()方法
方法是整个启动过程的核心:
- 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. 打印Banner
- Banner 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. 执行Runner
- callRunners(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. 准备应用上下文
方法完成以下工作:
- 将环境绑定到上下文
- 后置处理上下文
- 应用所有初始化器
- 发布ContextPrepared事件
- 注册主配置类bean定义
- 发布ContextLoaded事件
6. 刷新应用上下文
最终调用 - AbstractApplicationContext.refresh()
复制代码,这是Spring容器的核心刷新流程:
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // 1. 准备刷新
- prepareRefresh();
- // 2. 获取新的BeanFactory
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // 3. 准备BeanFactory
- prepareBeanFactory(beanFactory);
- try {
- // 4. 后置处理BeanFactory
- postProcessBeanFactory(beanFactory);
- // 5. 调用BeanFactoryPostProcessor
- invokeBeanFactoryPostProcessors(beanFactory);
- // 6. 注册BeanPostProcessor
- registerBeanPostProcessors(beanFactory);
- // 7. 初始化MessageSource
- initMessageSource();
- // 8. 初始化事件广播器
- initApplicationEventMulticaster();
- // 9. 初始化特殊bean(由子类实现)
- onRefresh();
- // 10. 注册监听器
- registerListeners();
- // 11. 初始化所有非懒加载单例
- finishBeanFactoryInitialization(beanFactory);
- // 12. 完成刷新
- finishRefresh();
- }
- catch (BeansException ex) {
- // 处理异常...
- }
- }
- }
复制代码
7. 内嵌Tomcat启动的关键:onRefresh()
对于Servlet Web应用, - ServletWebServerApplicationContext
复制代码重写了 方法:
- protected void onRefresh() {
- super.onRefresh();
- try {
- createWebServer();
- }
- catch (Throwable ex) {
- throw new ApplicationContextException("Unable to start web server", ex);
- }
- }
复制代码
是内嵌服务器启动的关键:
- private void createWebServer() {
- WebServer webServer = this.webServer;
- ServletContext servletContext = getServletContext();
- if (webServer == null && servletContext == null) {
- // 1. 获取WebServer工厂(Tomcat, Jetty或Undertow)
- ServletWebServerFactory factory = getWebServerFactory();
- // 2. 创建WebServer
- 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();
- }
复制代码
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. 配置Host
- tomcat.getHost().setAutoDeploy(false);
- configureEngine(tomcat.getEngine());
- // 5. 准备上下文
- prepareContext(tomcat.getHost(), initializers);
- // 6. 创建TomcatWebServer并启动
- return getTomcatWebServer(tomcat);
- }
复制代码
9. 启动Tomcat
在 构造函数中完成Tomcat的启动:
- public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
- this.tomcat = tomcat;
- this.autoStart = autoStart;
- initialize();
- }
- private void initialize() throws WebServerException {
- // 启动Tomcat
- this.tomcat.start();
- // 启动一个守护线程来等待停止命令
- startDaemonAwaitThread();
- }
复制代码
10. 自动配置的关键
整个过程中,自动配置是通过 注解中的 实现的:
- 在
- invokeBeanFactoryPostProcessors()
复制代码 阶段会处理自动配置 - AutoConfigurationImportSelector
复制代码 会加载- META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
复制代码 文件中的配置类- 对于Tomcat,会加载
- ServletWebServerFactoryAutoConfiguration
复制代码 - 这个配置类通过引入了等配置
总结流程
- 启动main方法
- 创建SpringApplication实例
- 运行run()方法
- 准备环境
- 创建应用上下文(AnnotationConfigServletWebServerApplicationContext)
- 准备上下文(注册配置类等)
- 刷新上下文(核心)
- 调用onRefresh()
- 创建内嵌Web服务器(Tomcat)
- 启动Tomcat
- 发布启动完成事件
- 执行Runner
到此这篇关于Spring Boot从main方法到内嵌Tomcat的全过程(自动化流程)的文章就介绍到这了,更多相关Spring Boot启动过程内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯! 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |