SpringBoot启动流程核心步骤:从入口到容器的完整解析
目录导读
-
SpringBoot启动的入口与核心类

-
启动流程第一阶段:初始化SpringApplication
-
启动流程第二阶段:运行SpringApplication
-
核心步骤详解:环境准备、上下文创建、自动配置
-
常见问题与面试问答
-
性能优化与调试建议
SpringBoot启动的入口与核心类
SpringBoot应用的启动始于一个简单的main方法,通常如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这里最核心的类是SpringApplication,它负责整个启动流程的编排,而@SpringBootApplication是一个组合注解,等效于@EnableAutoConfiguration + @ComponentScan + @SpringBootConfiguration。
问:@SpringBootApplication必须放在启动类上吗?
答:是的,它标记了配置类的位置,SpringBoot会基于该包路径进行组件扫描和自动配置。
启动流程第一阶段:初始化SpringApplication
当调用SpringApplication.run()时,首先会创建一个SpringApplication实例,初始化过程包括:
- 推断应用类型:通过类路径是否存在
DispatcherServlet或Reactive相关类,判断是Servlet(传统Web)还是Reactive(响应式)应用。 - 设置
BootstrapRegistryInitializer:从spring.factories中加载所有BootstrapRegistryInitializer实现,用于早期初始化。 - 设置
ApplicationContextInitializer:同样从spring.factories加载,这些初始化器会在容器刷新前对上下文进行定制。 - 设置
ApplicationListener:加载所有事件监听器,用于监听启动过程中的事件(如ApplicationStartedEvent、ApplicationReadyEvent)。 - 推断主启动类:通过堆栈信息找到调用
run方法的类,并记录为主配置类。
问:为什么需要推断应用类型?
答:因为不同Web类型需要不同的ApplicationContext实现(如AnnotationConfigServletWebServerApplicationContext vs AnnotationConfigReactiveWebServerApplicationContext),这一步决定了后续容器的选择。
启动流程第二阶段:运行SpringApplication
初始化完成后,执行run(String... args)方法,这是启动的核心阶段,主要步骤如下:
1 启动计时器
记录启动开始时间,用于后续打印启动耗时。
2 创建并配置ApplicationArguments
封装命令行参数,提供便捷的访问方式。
3 配置当前环境
- 如果有配置
spring.profiles.active,则激活对应的Profile。 - 从
spring.factories加载EnvironmentPostProcessor,对Environment进行后置处理(如加载随机数源、属性源)。
4 打印Banner
默认打印SpringBoot的ASCII艺术字Logo,可通过spring.banner.location自定义。
5 创建ApplicationContext
根据之前推断的应用类型,创建相应的ApplicationContext实例,对于Servlet应用,创建AnnotationConfigServletWebServerApplicationContext。
6 准备上下文(prepareContext)
这是最复杂的步骤之一,具体包括:
- 设置环境:将前面创建的
Environment绑定到上下文中。 - 应用初始化器:执行之前加载的
ApplicationContextInitializer。 - 注册启动参数:将
ApplicationArguments作为Bean注册到容器中。 - 加载Bean定义:扫描主配置类(即
Application.class),将其作为配置类加载。 - 处理事件:发送
ApplicationPreparedEvent事件。
7 刷新上下文(refreshContext)
调用AbstractApplicationContext.refresh(),这是Spring容器的核心启动过程,内含:
prepareRefresh():刷新前的准备工作。obtainFreshBeanFactory():创建或刷新BeanFactory。prepareBeanFactory():配置BeanFactory的标准特性。postProcessBeanFactory():后处理器扩展点。invokeBeanFactoryPostProcessors():执行BeanFactoryPostProcessor(包括自动配置的核心ConfigurationClassPostProcessor)。registerBeanPostProcessors():注册Bean后处理器。initMessageSource():初始化国际化资源。initApplicationEventMulticaster():初始化事件广播器。onRefresh():启动内嵌Web容器(如Tomcat、Jetty)。registerListeners():注册监听器。finishBeanFactoryInitialization():实例化所有非懒加载的单例Bean。finishRefresh():完成刷新,发出ContextRefreshedEvent。
8 启动后处理
afterRefresh():空方法,留给子类扩展。
9 发送启动完成事件
ApplicationStartedEvent:在上下文刷新后、但未调用CommandLineRunner和ApplicationRunner之前发出。ApplicationReadyEvent:在所有Runner执行完成后发出,表示应用已就绪。
10 返回ConfigurableApplicationContext
最终返回已准备好的上下文对象,用户可通过它获取Bean。
问:refreshContext过程中,内嵌Tomcat是在哪一步启动的?
答:在onRefresh()阶段。ServletWebServerApplicationContext会创建并启动内嵌Web服务器(如Tomcat),并绑定到指定端口。
核心步骤详解:环境准备、上下文创建、自动配置
1 环境准备
Environment对象持有应用运行时所需的所有配置属性(如application.properties、系统环境变量、命令行参数),多个PropertySource按优先级排序,相同的key会覆盖。
2 自动配置原理
自动配置的核心是@EnableAutoConfiguration,它通过AutoConfigurationImportSelector加载spring.factories中所有org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项,这些配置类中通常包含@ConditionalOnClass、@ConditionalOnMissingBean等条件注解,确保仅在满足条件时生效。
问:为什么自动配置类通常在Jar包中而不在项目里?
答:这是SpringBoot的“约定优于配置”设计,Jar包中的自动配置类通过SPI机制加载,用户只需引入依赖(如spring-boot-starter-web),自动配置类便会按条件生效。
常见问题与面试问答
Q1:SpringBoot启动流程中,哪些步骤可以干预?
A:多个扩展点:
ApplicationContextInitializer:在容器刷新前修改上下文。ApplicationRunner/CommandLineRunner:应用启动后执行自定义逻辑。EnvironmentPostProcessor:修改Environment属性源。SpringApplicationRunListener:监听启动各个阶段。
Q2:如果启动时找不到数据库连接会如何?
A:如果配置了spring.datasource.initialization-mode且数据库不可达,容器刷新时会抛出BeanCreationException,导致启动失败,可以通过@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)排除自动配置。
Q3:启动流程中Bean的实例化顺序是怎样的?
A:先实例化BeanFactoryPostProcessor相关Bean,然后是BeanPostProcessor,最后是普通Bean,同类型Bean按@Order注解或Ordered接口排序。@DependsOn可以显式指定依赖顺序。
性能优化与调试建议
- 显示启动耗时详情:在
application.properties中设置spring.autoconfigure.exclude可以排除不必要的自动配置类,减少加载时间。 - 使用
spring-boot-starter-actuator:通过/actuator/health端点查看应用状态,/actuator/beans查看Bean列表。 - 启用懒加载:
spring.main.lazy-initialization=true可延迟Bean初始化,提升启动速度(适用于非生产环境)。 - 诊断启动慢:添加
--debug参数,SpringBoot会输出自动配置报告和条件匹配日志,帮助定位耗时环节。
SpringBoot启动流程从@SpringBootApplication注解开始,经过初始化、环境构建、上下文刷新、自动配置加载、内嵌服务器启动,最终完成应用就绪,理解每一个步骤及其扩展点,不仅能帮助我们快速定位启动问题,还能对Spring框架的控制反转和依赖注入有更深层的认识,在实际开发中,合理利用各阶段的自定义能力,可以构建出更灵活、更健壮的应用。
参考来源:本研究综合了SpringBoot官方文档、开源社区源码分析文章及多个技术博客的精华内容,结合最新版本(2.7.x/3.x)的代码结构进行提炼与整合。