Spring Boot 启动原理与自动配置源码分析
入口点:@SpringBootApplication
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}@SpringBootApplication 是一个合成注解,组合了三个核心注解:
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 1. 标记为配置类
@EnableAutoConfiguration // 2. 开启自动配置(核心)
@ComponentScan(excludeFilters = { // 3. 组件扫描
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// ...
}| 注解 | 作用 |
|---|---|
@SpringBootConfiguration | 继承 @Configuration,表示该类是配置类 |
@EnableAutoConfiguration | 开启自动配置机制(核心) |
@ComponentScan | 默认扫描启动类所在包及其子包 |
启动流程(run 方法)
SpringApplication.run() 的完整流程可分解为以下几个阶段:
第一阶段:初始化
java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 1. 推断 Web 应用类型(NONE / SERVLET / REACTIVE)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2. 从 spring.factories 加载 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3. 从 spring.factories 加载 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 4. 推断主启动类(通过堆栈信息找到 main 方法所在类)
this.mainApplicationClass = deduceMainApplicationClass();
}关键点:spring.factories 是 Spring Boot 自动配置和 SPI 机制的基础。
第二阶段:运行
java
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 1. 创建 BootstrapContext
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 2. 配置 Headless 模式(避免无显示器环境出错)
configureHeadlessProperty();
// 3. 获取并启动 SpringApplicationRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext);
try {
// 4. 准备环境变量
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 5. 打印 Banner
Banner printedBanner = printBanner(environment);
// 6. 创建 ApplicationContext
context = createApplicationContext();
// 7. 准备上下文(加载 BeanDefinition、注入环境等)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 8. 刷新上下文(核心!启动 IOC 容器)
refreshContext(context);
// 9. 刷新后回调
afterRefresh(context, applicationArguments);
stopWatch.stop();
listeners.started(context);
// 10. 调用 CommandLineRunner 和 ApplicationRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
listeners.ready(context, Duration.ofMillis(stopWatch.getTotalTimeMillis()));
return context;
}流程图示
text
main()
│
├─ new SpringApplication()
│ ├─ 推断 Web 类型
│ ├─ 加载 Initializer
│ └─ 加载 Listener
│
└─ run()
├─ 创建 BootstrapContext
├─ 配置 Headless
├─ 获取 RunListeners → starting()
├─ 准备 Environment
├─ 打印 Banner
├─ 创建 ApplicationContext
├─ 准备 Context
│ ├─ 加载资源
│ ├─ 设置 Environment
│ ├─ 执行 Initializer
│ └─ 注册启动参数 Bean
│
├─ refreshContext() ← 核心!
│ └─ AbstractApplicationContext.refresh()
│ ├─ prepareRefresh() — 准备刷新
│ ├─ obtainFreshBeanFactory() — 获取 BeanFactory
│ ├─ prepareBeanFactory() — 准备 BeanFactory
│ ├─ postProcessBeanFactory() — BeanFactory 后置处理
│ ├─ invokeBeanFactoryPostProcessors() ← 自动配置入口!
│ ├─ registerBeanPostProcessors()
│ ├─ initMessageSource()
│ ├─ initApplicationEventMulticaster()
│ ├─ onRefresh()
│ ├─ registerListeners()
│ ├─ finishBeanFactoryInitialization() ← 实例化所有单例 Bean
│ └─ finishRefresh()
│
├─ afterRefresh()
├─ callRunners()
└─ return context自动配置原理(核心)
@EnableAutoConfiguration
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}关键点:
@Import(AutoConfigurationImportSelector.class)— 导入自动配置选择器AutoConfigurationImportSelector实现DeferredImportSelector接口
AutoConfigurationImportSelector
java
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware, Ordered {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 关键方法:获取自动配置类
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 1. 检查是否启用
if (!isEnabled(annotationMetadata)) return EMPTY_ENTRY;
// 2. 获取所有候选配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 3. 去重
configurations = removeDuplicates(configurations);
// 4. 排除指定的配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
configurations.removeAll(exclusions);
// 5. 根据条件过滤
configurations = filter(configurations, autoConfigurationMetadata);
return new AutoConfigurationEntry(configurations, exclusions);
}
}加载流程
text
getCandidateConfigurations()
→ SpringFactoriesLoader.loadFactoryNames()
→ 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
(Spring Boot 2.7+ 使用此文件替代旧版 spring.factories)Spring Boot 3.x 自动配置注册文件:
text
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
...加载到的配置类约 100-200 个(取决于 classpath 依赖)。
条件注解(@Conditional)
自动配置通过 @Conditional 系列注解实现按需加载,避免加载不必要的 Bean。
| 注解 | 判断条件 |
|---|---|
@ConditionalOnClass | classpath 中存在指定类 |
@ConditionalOnMissingClass | classpath 中不存在指定类 |
@ConditionalOnBean | 容器中已存在指定 Bean |
@ConditionalOnMissingBean | 容器中不存在指定 Bean |
@ConditionalOnProperty | 配置项存在且为指定值 |
@ConditionalOnResource | 资源文件存在 |
@ConditionalOnWebApplication | 当前 Web 应用类型 |
@ConditionalOnNotWebApplication | 当前不是 Web 应用 |
@ConditionalOnExpression | SpEL 表达式为 true |
示例:RedisAutoConfiguration
java
@AutoConfiguration
@ConditionalOnClass(RedisOperations.class) // 依赖 Jedis/Lettuce
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 如果用户没有自定义 redisTemplate,这个 Bean 才会生效
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}决策流程:
text
启动 → 加载 AutoConfiguration.imports → 142 个候选配置
→ 对每个配置应用 @Conditional 条件
→ RedisOperations.class 存在? ─→ 否 → 跳过
→ RedisConnectionFactory Bean 存在? ─→ 否 → 跳过
→ 用户自定义了 redisTemplate? ─→ 是 → 使用用户配置
→ 条件全部满足 → 创建 RedisTemplate Bean配置属性绑定
@EnableConfigurationProperties
java
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private String host = "localhost";
private int port = 6379;
private String password;
private int database = 0;
// ...
}绑定来源(优先级从高到低):
text
1. 命令行参数 --server.port=8080
2. JNDI 属性
3. 系统属性 System.getProperties()
4. OS 环境变量 SPRING_REDIS_HOST
5. application-{profile}.properties
6. application.properties
7. @PropertySource 注解宽松绑定(Relaxed Binding)
Spring Boot 将环境变量中的 SPRING_REDIS_HOST 自动绑定到 redis.host,支持多种命名风格:
text
环境变量: SPRING_REDIS_HOST
application.yml: spring.redis.host
系统属性: spring.redis.host嵌入式 Web 容器
Spring Boot 内置了 Tomcat、Jetty、Undertow 三种容器。
WebServer 初始化
java
@AutoConfiguration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public class ServletWebServerFactoryAutoConfiguration {
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}在 refreshContext() 的 onRefresh() 阶段:
java
// ServletWebServerApplicationContext.onRefresh()
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 创建并启动 Tomcat
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
// 获取 TomcatServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 创建并启动 Tomcat
this.webServer = factory.getWebServer(getSelfInitializer());
this.webServer.start();
}启动流程总结
text
┌──────────────────────────────────────────────────┐
│ @SpringBootApplication │
│ ├─ @SpringBootConfiguration → 配置类 │
│ ├─ @EnableAutoConfiguration → 自动配置 │
│ │ └─ AutoConfigurationImportSelector │
│ │ └─ 加载 AutoConfiguration.imports │
│ │ └─ @Conditional 条件过滤 │
│ │ └─ 创建配置中的 Bean │
│ └─ @ComponentScan → 扫描用户代码 │
│ │
│ SpringApplication.run() │
│ ├─ 准备环境 (Environment) │
│ ├─ 创建 ApplicationContext │
│ ├─ 准备上下文 (prepareContext) │
│ ├─ 刷新上下文 (refreshContext) ← 核心 │
│ │ └─ 12 步 refresh() 方法 │
│ └─ 执行 Runner (callRunners) │
└──────────────────────────────────────────────────┘常用调试方式
properties
# 查看自动配置报告
debug=true
# 查看自动配置决策
logging.level.org.springframework.boot.autoconfigure=DEBUG
# 查看 Bean 创建顺序
logging.level.org.springframework.beans.factory=TRACE启动时输出类似:
text
============================
AUTO-CONFIGURATION REPORT
============================
Positive matches:
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required class 'javax.sql.DataSource' (OnClassCondition)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)