SpringBoot启动过程与自动配置过程解读
作者:没事学AI
一、Spring Boot 启动流程
Spring Boot 应用的入口是 main
方法中的 SpringApplication.run()
,但这行代码背后藏着一整套“初始化-配置-启动”的流水线。
我们可以将其分为构造阶段和运行阶段两大步,每一步都有明确的职责边界。
1.1 构造阶段:初始化核心组件
SpringApplication
实例的创建是启动的第一步,这个阶段的核心是“搭骨架”——确定应用类型、加载初始化器和监听器,为后续运行铺路。
- 验证主类合法性:通过
Assert.notNull
确保传入的主配置类(标注@SpringBootApplication
的类)非空,这是整个应用的“根”。 - 推断应用类型:通过
WebApplicationType.deduceFromClasspath()
检查类路径中是否存在DispatcherServlet
(MVC)或DispatcherHandler
(WebFlux),自动判断是SERVLET
、REACTIVE
还是非 Web 应用(NONE
)。 - 加载初始化器与监听器:从
META-INF/spring.factories
中读取ApplicationContextInitializer
和ApplicationListener
的实现类。这些组件是 Spring Boot 的“扩展点”,例如初始化器可用于预先配置上下文,监听器可监听启动各阶段事件。 - 定位主程序类:通过栈追踪找到调用
main
方法的类,作为应用的入口标记。
关键源码片段:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
1.2 运行阶段:从环境准备到容器启动
SpringApplication.run()
方法是真正的“执行引擎”,可细分为 10 个关键步骤,环环相扣:
- 启动监控与监听器:通过
StopWatch
记录启动时间,同时触发SpringApplicationRunListeners.starting()
,通知所有监听器“应用开始启动”。 - 环境配置:创建
ConfigurableEnvironment
(根据应用类型选择StandardServletEnvironment
或StandardReactiveWebEnvironment
),并加载系统变量、配置文件(如application.yml
)等。完成后调用environmentPrepared
事件,允许监听器对环境进行二次调整。 - 打印 Banner:默认打印 Spring Boot 版本信息,可通过
resources/banner.txt
自定义(支持 ASCII 艺术或变量替换)。 - 创建应用上下文:根据应用类型生成对应的 IOC 容器,例如 Servlet 应用使用
AnnotationConfigServletWebServerApplicationContext
。 - 上下文准备:将环境、命令行参数等注入上下文,执行初始化器的
initialize
方法,并触发contextPrepared
事件。 - 上下文刷新:调用
refreshContext
,触发 Spring 容器的核心流程(Bean 定义加载、实例化、依赖注入等),同时启动嵌入式服务器(如 Tomcat)。 - 收尾工作:执行
afterRefresh
(预留扩展点),停止计时器,并触发started
事件。 - 回调自定义逻辑:从容器中获取
ApplicationRunner
和CommandLineRunner
的实现类,按顺序执行其run
方法(适合启动后初始化数据等操作)。 - 启动完成:触发
running
事件,应用正式就绪。 - 异常处理:若启动失败,调用
failed
事件,打印异常并关闭上下文。
实战技巧:若需在启动后执行初始化逻辑(如加载缓存),优先使用 ApplicationRunner
(支持 ApplicationArguments
解析)而非 CommandLineRunner
(直接接收字符串数组)。
二、自动配置:Spring Boot 的“智能配置”核心
Spring Boot 最令人称道的“自动配置”,本质是“基于条件的约定配置”。
它通过一套规则判断环境中存在的依赖,自动装配对应的组件,避免手动编写 XML 或 @Bean
配置。
2.1 自动配置的底层原理
自动配置的触发点是 @EnableAutoConfiguration
注解(被 @SpringBootApplication
间接包含),其核心逻辑在 AutoConfigurationImportSelector
中:
- 加载候选配置类:通过
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader)
,扫描所有 Jar 包的META-INF/spring.factories
,获取EnableAutoConfiguration
对应的配置类列表(如HttpEncodingAutoConfiguration
、DataSourceAutoConfiguration
等)。 - 过滤与去重:移除重复或被排除的配置类(通过
@SpringBootApplication(exclude = ...)
指定),再通过条件注解(如@ConditionalOnClass
)判断配置类是否生效。 - 注入容器:将生效的配置类加载到容器中,其内部的
@Bean
方法会自动生成组件。
关键源码片段:
// AutoConfigurationImportSelector 中加载候选配置类的逻辑 protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories"); return configurations; }
2.2 条件注解:自动配置的“开关”
自动配置的“智能”依赖于 @Conditional
系列注解,它们决定了一个配置类或 @Bean
方法是否生效。
常用条件注解如下:
注解 | 作用 | 示例场景 |
---|---|---|
@ConditionalOnClass | 类路径存在指定类时生效 | 检测到 DataSource.class 时配置数据源 |
@ConditionalOnMissingBean | 容器中不存在指定 Bean 时生效 | 若用户未定义 RestTemplate,则自动配置默认实例 |
@ConditionalOnProperty | 配置项满足条件时生效 | 通过 spring.datasource.enabled=true 控制数据源是否启用 |
@ConditionalOnWebApplication | 仅 Web 应用生效 | 配置 DispatcherServlet |
实战案例:
HttpEncodingAutoConfiguration
(HTTP 编码自动配置)的条件判断:
@Configuration @EnableConfigurationProperties(HttpProperties.class) // 绑定配置文件属性 @ConditionalOnWebApplication(type = Type.SERVLET) // 仅 Servlet 应用生效 @ConditionalOnClass(CharacterEncodingFilter.class) // 存在字符编码过滤器类时生效 @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration { @Bean @ConditionalOnMissingBean // 若用户未定义,则自动配置 public CharacterEncodingFilter characterEncodingFilter() { // 从 HttpProperties 中读取配置(如 spring.http.encoding.charset=utf-8) CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter(); filter.setEncoding(properties.getCharset().name()); return filter; } }
技巧:
若需禁用某个自动配置(如默认的数据源配置),可通过
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
或配置
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
2.3 自定义自动配置:扩展 Spring Boot
若需为自己的组件实现自动配置(如公司内部 SDK),需遵循以下步骤:
编写配置类:使用 @Configuration
和条件注解定义组件装配逻辑,通过 @EnableConfigurationProperties
绑定配置属性。
注册配置类:在 Jar 包的 META-INF/spring.factories
中添加:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.sdk.MyComponentAutoConfiguration
添加配置元数据:在 META-INF/spring-configuration-metadata.json
中定义配置项的描述(IDE 会自动提示),例如:
{ "properties": [ { "name": "example.sdk.enabled", "type": "java.lang.Boolean", "defaultValue": true, "description": "是否启用 SDK 组件" } ] }
验证方法:启动应用时添加 --debug
参数,控制台会打印自动配置报告,显示哪些配置类生效(Positive matches)或不生效(Negative matches)。
三、总结:Spring Boot 便捷性的本质
Spring Boot 的启动流程和自动配置,本质是“约定优于配置”的极致体现:
- 启动流程通过标准化的步骤,将 Spring 容器的初始化与嵌入式服务器的启动无缝衔接,减少手动干预。
- 自动配置基于条件注解和
spring.factories
机制,实现了“依赖驱动配置”,让开发者专注于业务逻辑而非框架整合。
理解这些原理后,不仅能更高效地排查问题(如启动慢、自动配置失效),还能灵活扩展 Spring Boot(如自定义 starters 或启动流程)。
记住:Spring Boot 不是“魔法”,而是对 Spring 框架的“工程化封装”——看透其源码,就能真正掌控它。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。