好的,这是 Spring Boot 最核心的机制,面试中属于必考深度题。我会从启动入口到自动配置加载,完整拆解整个流程。
Spring Boot 启动全流程
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这行代码背后发生了7个关键阶段:
阶段一:构造 SpringApplication(实例化)
// SpringApplication.run() 内部
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return new SpringApplication(primarySource).run(args); // 先构造,再运行
}
构造过程(推断应用类型 + 加载初始化器):
| 步骤 | 操作 | 关键代码 |
|---|---|---|
| 1. 推断应用类型 | 检查类路径判断是 Servlet/Reactive/None | WebApplicationType.deduceFromClasspath() |
| 2. 加载 BootstrapRegistryInitializer | 从 spring.factories 加载 | getSpringFactoriesInstances() |
| 3. 加载 ApplicationContextInitializer | 上下文初始化器 | 同上 |
| 4. 加载 ApplicationListener | 应用事件监听器 | 同上 |
| 5. 推断主类 | 通过堆栈分析找到包含 main 方法的类 | deduceMainApplicationClass() |
推断应用类型的逻辑:
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null)
&& !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
return WebApplicationType.REACTIVE; // WebFlux
}
for (String className : SERVLET_INDICATOR_CLASSES) { // Servlet 相关类
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE; // 非 Web
}
}
return WebApplicationType.SERVLET; // Spring MVC(默认)
}
阶段二:运行 SpringApplication(run 方法核心)
public ConfigurableApplicationContext run(String... args) {
// 1. 启动计时器
StartupStep startupStep = this.applicationStartup.start("spring.boot.application.starting");
// 2. 创建 DefaultBootstrapContext(引导上下文)
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 3. 配置 Headless 模式(无显示器环境)
configureHeadlessProperty();
// 4. 发布启动事件(监听器可以在此介入)
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 5. 封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 6. 【关键】准备 Environment(加载配置文件)
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 7. 打印 Banner
Banner printedBanner = printBanner(environment);
// 8. 【关键】创建 ApplicationContext(根据类型创建)
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 9. 【核心】准备 Context(加载自动配置在此!)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 10. 【核心】刷新 Context(Bean 定义加载 + 实例化)
refreshContext(context);
// 11. 后置处理
afterRefresh(context, applicationArguments);
startupStep.end();
listeners.started(context);
// 12. 执行 Runner(ApplicationRunner / CommandLineRunner)
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
阶段三:准备 Environment(配置加载)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 1. 创建或获取 Environment(StandardServletEnvironment)
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 2. 配置 PropertySources 和 Profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 3. 【关键】发布环境准备事件,ConfigFileApplicationListener 响应
// 这里加载 application.yml / application-{profile}.yml
listeners.environmentPrepared(bootstrapContext, environment);
return environment;
}
ConfigFileApplicationListener 的加载逻辑:
// 加载顺序(低优先级 → 高优先级,高覆盖低)
1. jar 外部的 application-{profile}.properties/yml
2. jar 内部的 application-{profile}.properties/yml
3. jar 外部的 application.properties/yml
4. jar 内部的 application.properties/yml
阶段四:创建 ApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.apply(this.webApplicationType);
}
// 根据类型创建不同上下文
switch (webApplicationType) {
case SERVLET:
// AnnotationConfigServletWebServerApplicationContext
return new ServletWebServerApplicationContext();
case REACTIVE:
// AnnotationConfigReactiveWebServerApplicationContext
return new ReactiveWebServerApplicationContext();
default:
// AnnotationConfigApplicationContext
return new ApplicationContext();
}
阶段五:准备 Context(【核心】自动配置入口)
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 1. 设置 Environment
context.setEnvironment(environment);
// 2. 后置处理 Context(注册 beanNameGenerator、resourceLoader 等)
postProcessApplicationContext(context);
// 3. 【关键】执行 ApplicationContextInitializer
applyInitializers(context);
// 4. 发布 ContextPrepared 事件
listeners.contextPrepared(context);
// 5. 注册 Spring Boot 特殊 Bean
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 6. 【核心】加载主类(@SpringBootApplication 所在类)
Set<Object> sources = getAllSources();
load(context, sources.toArray(new Object[0])); // 注册为 BeanDefinition
// 7. 发布 ContextLoaded 事件
listeners.contextLoaded(context);
}
阶段六:刷新 Context(【核心】自动配置加载)
refreshContext() → AbstractApplicationContext.refresh():
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新(设置启动时间、状态等)
prepareRefresh();
// 2. 获取 BeanFactory(DefaultListableBeanFactory)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory(注册类加载器、表达式解析器等)
prepareBeanFactory(beanFactory);
try {
// 4. 子类扩展(ServletContext 相关处理)
postProcessBeanFactory(beanFactory);
// 5. 【关键】执行 BeanFactoryPostProcessor
// ConfigurationClassPostProcessor 在这里处理 @Configuration 类
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 7. 初始化 MessageSource
initMessageSource();
// 8. 初始化 ApplicationEventMulticaster
initApplicationEventMulticaster();
// 9. 子类扩展(创建 WebServer,如 Tomcat)
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 【关键】实例化所有非懒加载的单例 Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新(发布 ContextRefreshedEvent)
finishRefresh();
}
// ...
}
}
6.1 核心:invokeBeanFactoryPostProcessors
// ConfigurationClassPostProcessor 处理 @Configuration 类
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 解析 @Configuration 类,包括 @ComponentScan、@Import、@Bean 等
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
解析主类的 @SpringBootApplication:
@SpringBootApplication // 组合注解
public class Application { }
// 等价于:
@Configuration
@EnableAutoConfiguration // 【核心】开启自动配置
@ComponentScan // 组件扫描
public class Application { }
阶段七:@EnableAutoConfiguration 原理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 将主类所在包注册为自动配置包
@Import(AutoConfigurationImportSelector.class) // 【核心】导入自动配置类
public @interface EnableAutoConfiguration {}
7.1 AutoConfigurationImportSelector 加载流程
public class AutoConfigurationImportSelector implements
DeferredImportSelector, BeanClassLoaderAware, ... {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 检查是否启用自动配置(spring.boot.enableautoconfiguration)
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 2. 从 META-INF/spring-autoconfigure-metadata.properties 加载元数据
AutoConfigurationMetadata autoConfigurationMetadata =
AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
// 3. 【关键】获取候选自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 4. 去重
configurations = removeDuplicates(configurations);
// 5. 获取需要排除的类(@EnableAutoConfiguration(exclude=...))
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 6. 检查排除类合法性
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 7. 【关键】按条件过滤(@Conditional 评估)
configurations = getConfigurationClassFilter().filter(configurations);
// 8. 发布自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
}
7.2 获取候选配置类(SPI 机制)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 从 META-INF/spring.factories 加载
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories");
return configurations;
}
// spring.factories 示例(Spring Boot 2.7+ 改为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
...(约 100+ 个)
7.3 条件过滤(@Conditional 生效)
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
// 获取所有条件过滤器(OnClassCondition, OnBeanCondition, OnPropertyCondition 等)
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
// 批量匹配条件(优化性能,避免每个类单独检查)
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null; // 标记为跳过
skipped = true;
}
}
}
// 收集通过的类
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
return result;
}
完整流程图
┌─────────────────────────────────────────────────────────────────┐
│ SpringApplication.run() │
├─────────────────────────────────────────────────────────────────┤
│ 1. 构造 SpringApplication │
│ ├── 推断 Web 类型 (Servlet/Reactive/None) │
│ ├── 加载 spring.factories: BootstrapRegistryInitializer │
│ ├── 加载 spring.factories: ApplicationContextInitializer │
│ └── 加载 spring.factories: ApplicationListener │
├─────────────────────────────────────────────────────────────────┤
│ 2. 运行 run() │
│ ├── 发布 Starting 事件 │
│ ├── 准备 Environment(加载 application.yml) │
│ ├── 打印 Banner │
│ ├── 创建 ApplicationContext │
│ ├── 准备 Context │
│ │ ├── 执行 ApplicationContextInitializer │
│ │ ├── 加载主类(@SpringBootApplication) │
│ │ └── 发布 ContextPrepared/ContextLoaded 事件 │
│ ├── 【核心】刷新 Context │
│ │ ├── invokeBeanFactoryPostProcessors │
│ │ │ └── ConfigurationClassPostProcessor │
│ │ │ └── 解析 @Configuration │
│ │ │ ├── 处理 @ComponentScan(包扫描) │
│ │ │ ├── 处理 @Import(导入配置类) │
│ │ │ │ └── @EnableAutoConfiguration │
│ │ │ │ └── AutoConfigurationImportSelector │
│ │ │ │ ├── 读取 spring.factories │
│ │ │ │ ├── 获取 100+ 自动配置类 │
│ │ │ │ ├── @Conditional 过滤 │
│ │ │ │ │ ├── OnClassCondition │
│ │ │ │ │ ├── OnBeanCondition │
│ │ │ │ │ └── OnPropertyCondition │
│ │ │ │ └── 注册通过的 BeanDefinition │
│ │ │ └── 处理 @Bean 方法 │
│ │ ├── 注册 BeanPostProcessor │
│ │ ├── onRefresh()(创建 WebServer,如 Tomcat) │
│ │ ├── finishBeanFactoryInitialization(实例化单例 Bean) │
│ │ └── finishRefresh() │
│ ├── 执行 ApplicationRunner / CommandLineRunner │
│ └── 发布 Running 事件 │
└─────────────────────────────────────────────────────────────────┘
关键优化点(面试加分项)
| 优化 | 说明 | 版本 |
|---|---|---|
| spring-autoconfigure-metadata.properties | 编译期生成条件元数据,避免运行时反射检查类是否存在 | 2.0+ |
| DeferredImportSelector | 延迟导入,确保用户配置优先于自动配置 | 1.5+ |
| 批量条件评估 | 一次检查多个类,减少 ClassLoader 查询次数 | 2.0+ |
| AOT 处理(Spring Boot 3+) | 原生镜像支持,启动时无需反射扫描 | 3.0+ |
面试回答模板
"Spring Boot 启动流程分为构造和运行两个阶段。构造阶段推断应用类型、加载初始化器;运行阶段先准备 Environment 加载配置文件,然后创建 ApplicationContext。核心是 refresh 过程,其中 ConfigurationClassPostProcessor 解析主类的 @SpringBootApplication,触发 @EnableAutoConfiguration,通过 AutoConfigurationImportSelector 从 spring.factories 读取自动配置类,再经过 @Conditional 条件过滤,最终注册符合条件的 BeanDefinition 到容器。"
、