Spring Boot应用的启动流程
揭秘Spring Boot启动流程:核心是
SpringApplication.run()创建并刷新ApplicationContext,利用自动配置机制,完成Bean创建及内嵌服务器启动。
我们来详细、分步地解析一下 Spring Boot 应用的启动流程。
Spring Boot 的启动流程核心目标是:创建并配置 Spring 的 ApplicationContext (应用上下文)。这个过程被 SpringApplication.run() 方法高度封装,它自动化了大量原本需要手动配置的工作。
整个流程可以分为三大阶段:
SpringApplication对象的初始化阶段:准备启动所需的基础环境。run()方法执行阶段:这是启动的核心,包括创建环境、创建ApplicationContext、执行刷新等。ApplicationContext刷新阶段:这是经典的 Spring IoC 容器启动过程,也是 Bean 创建和装配的核心。
下面我们来详细分解这个过程。
零、起点:main 方法
一切都始于一个标准的 Java main 方法。
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
@SpringBootApplication: 这是一个复合注解,是启动流程的第一个关键配置。它包含了:@SpringBootConfiguration: 继承自@Configuration,表明这个类是一个 Spring 配置类。@EnableAutoConfiguration: 启动自动配置的核心。它会告诉 Spring Boot 根据 classpath 中的依赖,自动配置项目。@ComponentScan: 自动扫描该类所在包及其子包下的 Spring 组件(如@Component,@Service,@RestController等)。
SpringApplication.run(...): 这是整个启动流程的入口,所有魔法都从这里开始。
一、SpringApplication 对象的初始化阶段
当我们调用 SpringApplication.run(MyApplication.class, args) 时,它内部首先会创建一个 SpringApplication 实例。在这个构造函数中,它会做以下几件重要的事情:
- 推断应用类型:通过检查 classpath,判断当前是哪种类型的应用。
REACTIVE: 如果存在spring-webflux。SERVLET: 如果存在spring-webmvc(这是最常见的)。NONE: 非 Web 应用。
- 加载 Initializers 和 Listeners:使用 Spring 的 SPI (Service Provider Interface) 机制,从
META-INF/spring.factories文件中加载ApplicationContextInitializer和ApplicationListener接口的实现类。这些类会在启动过程中的特定时间点被回调,允许我们进行自定义扩展。 - 推断主应用类 (Main Class):通过分析堆栈信息,找出包含
main方法的类,即MyApplication.class。
至此,一个配置了基本信息的 SpringApplication 对象准备就绪。
二、run() 方法执行阶段
这是启动流程的核心和主干。
- 创建并启动
StopWatch:用于记录启动耗时。 - 创建并配置
Environment(环境):- 创建一个
ConfigurableEnvironment对象。 - 加载和整合各种配置源,形成一个统一的配置视图。加载顺序有优先级,后面的会覆盖前面的:
- 命令行参数 (
--server.port=9090) - JVM 系统属性 (
-D...) - 操作系统环境变量
application-{profile}.properties或.yml文件application.properties或.yml文件@PropertySource注解指定的配置- 默认属性
- 命令行参数 (
- 创建一个
- 打印 Banner:在控制台输出 Spring Boot 的横幅,你可以在
src/main/resources下创建banner.txt文件来定制它。 - 创建
ApplicationContext(应用上下文):- 根据之前推断的应用类型,创建相应的
ApplicationContext实例。 - 对于 Web 应用,通常是
AnnotationConfigServletWebServerApplicationContext。 - 对于响应式应用,是
AnnotationConfigReactiveWebServerApplicationContext。
- 根据之前推断的应用类型,创建相应的
- 预处理
ApplicationContext(prepareContext):- 将之前创建的
Environment设置到ApplicationContext中。 - 调用之前加载的
ApplicationContextInitializer的initialize方法,对ApplicationContext进行进一步的配置。 - 加载所有的 Bean 定义(
BeanDefinition),包括主配置类和你自己定义的 Bean。此时 Bean 还没有被实例化。
- 将之前创建的
- 刷新
ApplicationContext(refreshContext):- 这是整个启动流程中最核心、最复杂的一步。它会触发 Spring 容器的刷新机制,完成所有 Bean 的创建、依赖注入和初始化。我们将在下一节详细讲解。
- 刷新后处理 (
afterRefresh):提供一个空的模板方法,用于子类扩展。 - 调用
Runner:- 在
ApplicationContext完全准备好之后,Spring Boot 会查找所有实现了ApplicationRunner和CommandLineRunner接口的 Bean。 - 按照
@Order注解或Ordered接口定义的顺序,依次调用它们的run方法。这通常用于执行一些应用启动后需要立即运行的任务(如数据初始化、启动定时任务等)。
- 在
- 应用就绪:至此,应用已成功启动,并准备好接收请求。
run方法返回ConfigurableApplicationContext实例。
三、ApplicationContext 刷新阶段 (refreshContext)
这一步实际上是调用了 Spring 框架自身的 AbstractApplicationContext.refresh() 方法。它是 Spring IoC 容器生命周期的核心。其中与 Spring Boot 启动最相关的步骤是:
invokeBeanFactoryPostProcessors(调用 BeanFactory 后置处理器):- 自动配置的魔法发生在这里!
@EnableAutoConfiguration注解通过@Import(AutoConfigurationImportSelector.class)导入了AutoConfigurationImportSelector。- 这个
Selector会去扫描所有依赖 JAR 包中的META-INF/spring.factories(或 Spring Boot 3+ 的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports) 文件。 - 它会加载文件中列出的所有自动配置类 (例如
DataSourceAutoConfiguration,WebMvcAutoConfiguration等)。 - 这些自动配置类本身都是
@Configuration配置类,它们内部使用了大量的@Conditional注解(如@ConditionalOnClass,@ConditionalOnBean,@ConditionalOnProperty)。 - Spring Boot 会根据当前的环境(比如 classpath 中是否存在某个类、是否已存在某个 Bean、配置文件中是否有某个属性)来判断这些自动配置类是否生效。
- 如果生效,这些配置类中定义的 Bean 就会被注册到
ApplicationContext中。例如,如果 classpath 中有tomcat-embed-core.jar并且没有用户自定义的TomcatServletWebServerFactoryBean,那么ServletWebServerFactoryAutoConfiguration就会生效,并创建一个 Tomcat 服务器的 Bean。
registerBeanPostProcessors(注册 Bean 后置处理器):注册所有BeanPostProcessor,它们可以在 Bean 初始化前后进行干预。onRefresh(刷新):- 对于 Web 应用,在这一步会创建并启动内嵌的 Web 服务器(如 Tomcat, Jetty, Undertow)。服务器会开始监听指定的端口。
finishBeanFactoryInitialization(完成 BeanFactory 初始化):- 实例化所有剩余的非懒加载单例 Bean。
- 这个过程会进行依赖注入(
@Autowired)、属性填充、执行初始化方法(如@PostConstruct,afterPropertiesSet)等。
finishRefresh(完成刷新):- 发布
ContextRefreshedEvent事件,通知所有监听器容器已经刷新完毕。
- 发布
总结 & 流程图
一图胜千言,简化版流程图:
main() 方法
│
└──> SpringApplication.run()
│
├─ 1. 创建 SpringApplication 实例 (推断应用类型, 加载 SPI 扩展)
│
├─ 2. run() 方法执行
│ ├── 准备 Environment (加载 application.properties 等配置)
│ ├── 打印 Banner
│ ├── 创建 ApplicationContext (例如: AnnotationConfigServletWebServerApplicationContext)
│ ├── prepareContext (准备上下文, 加载 BeanDefinition)
│ │
│ └── refreshContext (刷新上下文) <-- 核心
│ ├── invokeBeanFactoryPostProcessors() <-- 自动配置在这里生效
│ │ (加载 META-INF/spring.factories 中的自动配置类, 并根据 @Conditional 判断是否生效)
│ │
│ ├── onRefresh() <-- 启动内嵌 Tomcat/Jetty 等 Web 服务器
│ │
│ └── finishBeanFactoryInitialization() <-- 实例化所有单例 Bean, 完成依赖注入
│
├─ 3. 调用 ApplicationRunner 和 CommandLineRunner
│
└──> 应用启动完成,可以处理请求
总而言之,Spring Boot 的启动流程是一个高度自动化和可扩展的过程。它以 SpringApplication.run() 为核心,通过自动配置机制,智能地根据项目依赖和用户配置来组装一个功能完备的 Spring 应用,极大地简化了开发者的工作。