关键词:Spring Boot、启动流程、源码解析、IoC容器、自动配置
摘要:本文深入分析Spring Boot的启动流程,结合核心源码详解从run()
方法到嵌入式服务器启动的每一步操作,揭秘自动配置原理及扩展点。
一、为什么需要掌握启动流程?
Spring Boot以其约定大于配置、快速启动的特性成为Java微服务开发的首选框架。理解其启动流程,能帮助我们:
- 🔧 定制化扩展:自定义启动加载过程
- ⚡ 性能优化:加速应用启动(大型项目启动耗时从分钟级降到秒级)
- 🐞 故障排查:解决初始化阶段的诡异Bug
- 💡 深入理解框架:打通Spring Boot任督二脉
下面我们将结合源码,深入剖析Spring Boot启动的每一个关键步骤。
二、启动流程总览(10步图解)
flowchart TB
A[SpringApplication.run()] --> B[初始化SpringApplicationRunListeners]
B --> C[准备环境Environment]
C --> D[打印Banner]
D --> E[创建ApplicationContext]
E --> F[准备上下文]
F --> G[刷新上下文<br><font color='#FF0000'>(最核心)</font>]
G --> H[加载自动配置]
G --> I[实例化单例Bean]
I --> J[启动嵌入式服务器]
J --> K[发布Ready事件]
三、启动流程源码级分解
步骤1: SpringApplication初始化
// 源码位置:SpringApplication.java
public SpringApplication(Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 1.推断应用类型
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 2.加载Initializer
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 3.加载Listener
this.mainApplicationClass = deduceMainApplicationClass(); // 4.推断主类
}
作用说明:
推断应用类型(Servlet/Reactive/None)通过检测类路径是否存在:
javax.servlet.Servlet
和org.springframework.web.context.ConfigurableWebApplicationContext
→ SERVLETorg.springframework.web.reactive.DispatcherHandler
→ REACTIVE- 否则 → NONE
通过SPI机制加载
META-INF/spring.factories
中定义的拓展组件
步骤2: 执行run()方法
// 源码位置:SpringApplication.java
public ConfigurableApplicationContext run(String... args) {
// 1. 启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 初始化SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(); // 发布ApplicationStartingEvent
// 3. 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 4. 打印Banner
Banner printedBanner = printBanner(environment);
// 5. 创建ApplicationContext
context = createApplicationContext();
// 6. 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 7. 刷新上下文(核心!)
refreshContext(context);
// 8. 执行Runner
callRunners(context, applicationArguments);
// 9. 完成启动
listeners.started(context);
return context;
}
步骤3: 环境准备(Environment)
private ConfigurableEnvironment prepareEnvironment(...) {
// 创建环境对象(Servlet环境或标准环境)
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 加载配置源(application.properties/yml)
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared(environment);
// 绑定SpringApplication配置
bindToSpringApplication(environment);
return environment;
}
步骤4: 创建IoC容器
根据应用类型创建不同类型的上下文:
// 源码位置:SpringApplication.java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
// 默认实现
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
};
步骤5: 刷新上下文(最核心步骤)
// 源码位置:SpringApplication.java
private void refreshContext(ConfigurableApplicationContext context) {
// 调用AbstractApplicationContext.refresh()
refresh(context);
}
// 源码位置:AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// [1] 准备刷新工作
prepareRefresh();
// [2] 获取新的BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// [3] 配置BeanFactory(注册环境等组件)
prepareBeanFactory(beanFactory);
try {
// [4] 后处理BeanFactory
postProcessBeanFactory(beanFactory);
// [5] 执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// [6] 注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// [7] 初始化MessageSource(国际化)
initMessageSource();
// [8] 初始化事件广播器
initApplicationEventMulticaster();
// [9] 初始化特殊Bean
onRefresh();
// [10] 注册监听器
registerListeners();
// [11] 实例化非懒加载的单例Bean
finishBeanFactoryInitialization(beanFactory);
// [12] 完成刷新
finishRefresh();
}
}
}
关键子步骤:自动配置生效过程
// 源码位置:PostProcessorRegistrationDelegate.java
public static void invokeBeanFactoryPostProcessors(...) {
// 处理BeanDefinitionRegistryPostProcessor
processConfigBeanDefinitions(registry);
}
private static void processConfigBeanDefinitions(...) {
// 创建ConfigurationClassParser解析@Configuration类
parser.parse(candidates);
// 加载自动配置类
Set<String> candidates = new LinkedHashSet<>(configCandidates);
AutoConfigurationImportSelector.selectImports() // 关键方法
}
自动配置选择器核心逻辑:
// 源码位置:AutoConfigurationImportSelector.java
protected List<String> getCandidateConfigurations(...) {
// 从META-INF/spring.factories加载配置
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
EnableAutoConfiguration.class, getBeanClassLoader());
// 应用条件过滤(@ConditionalOnClass等)
configurations = filter(configurations, autoConfigurationMetadata);
return configurations;
}
四、关键扩展点实战
扩展点1:自定义ApplicationRunner
@Component
@Order(1) // 控制执行顺序
public class CacheInitializer implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("初始化缓存数据...");
// 实际业务逻辑
}
}
扩展点2:自定义事件监听
@Component
public class StartupMonitorListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("应用启动完成,耗时:" +
TimeUnit.NANOSECONDS.toMillis(event.getTimestamp()) + "ms");
}
}
扩展点3:自定义BeanPostProcessor
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if(bean instanceof Controller) {
System.out.println("Controller初始化完成: " + beanName);
}
return bean;
}
}
五、性能优化实践
- 减少组件扫描范围
@SpringBootApplication(scanBasePackages = "com.example.core")
- 排除不必要的自动配置
@EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
KafkaAutoConfiguration.class
})
- 启用懒初始化(慎用)
spring.main.lazy-initialization=true
- 关闭JMX监控(节省30-50ms)
spring.jmx.enabled=false
六、常见面试题
Q1: @SpringBootApplication注解做了哪些事?
A: 该注解是三个核心注解的组合:
@SpringBootConfiguration
:标识为配置类@EnableAutoConfiguration
:启用自动配置@ComponentScan
:组件扫描(默认当前包)
Q2: 自动配置是如何实现的?
A: 通过@EnableAutoConfiguration
引入AutoConfigurationImportSelector
,该选择器:
- 从
META-INF/spring.factories
加载配置类 - 过滤掉缺少依赖的配置(通过
@ConditionalOnClass
等条件注解) - 应用排序规则
Q3: 如何加速Spring Boot启动?
优化方案:
- 减小@ComponentScan范围
- 排除不必要的自动配置
- 使用
@Lazy
延迟初始化 - 关闭JMX、actuator等非必要模块
七、总结
Spring Boot的启动过程本质上是IoC容器的初始化过程,核心亮点在于:
- 事件驱动架构:通过11种启动事件解耦各阶段
- 条件化自动配置:按需加载超过300+自动配置类
- 嵌入式容器:无缝集成Tomcat/Jetty等服务器
- SPI扩展机制:通过spring.factories实现插件化
掌握启动流程后,你可以:
- 定制自己的启动初始化逻辑
- 解决Bean初始化顺序问题
- 实现秒级启动的微服务
- 深度优化Spring Boot应用