SpringBoot启动过程源码深度解析:从main()方法到容器就绪的全流程剖析
本文详细解析了SpringBoot启动流程,主要包含:1)启动流程全景图,从SpringApplication构造到容器刷新;2)核心步骤详解,包括环境准备、上下文创建和容器刷新;3)关键扩展点分析,如ApplicationContextInitializer和SpringApplicationRunListener;4)配置文件加载机制与多环境支持;5)内嵌Web服务器启动原理;6)启动优化建议
一、SpringBoot启动流程全景图
在深入源码之前,我们先通过一张全景图了解SpringBoot启动的整体流程:

这个流程看似简单,但每个步骤都包含了丰富的内部逻辑和扩展点。接下来我们逐一深入分析。
二、SpringApplication对象构造过程
1. 推测Web应用类型
SpringBoot在启动时会自动推测应用类型,这是整个启动过程的基础决策:
// SpringApplication构造函数中的类型推测逻辑
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null)
&& !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
return WebApplicationType.REACTIVE; // 响应式Web应用
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE; // 非Web应用
}
}
return WebApplicationType.SERVLET; // Servlet Web应用
}
三种应用类型说明:
-
SERVLET:传统Servlet Web应用(Spring MVC)
-
REACTIVE:响应式Web应用(WebFlux)
-
NONE:非Web应用(如定时任务、批处理等)
2. 加载关键组件
SpringBoot通过SPI机制从META-INF/spring.factories加载扩展组件:
// 从spring.factories加载关键组件 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
加载的核心组件类型:
| 组件类型 | 作用 | 典型实现 |
|---|---|---|
ApplicationContextInitializer |
Spring容器初始化器 | ConditionEvaluationReportLoggingListener |
ApplicationListener |
事件监听器 | ConfigFileApplicationListener |
SpringApplicationRunListener |
启动过程监听器 | EventPublishingRunListener |
三、run()方法执行流程详解
步骤1:启动前的准备工作
public ConfigurableApplicationContext run(String... args) {
// 1. 创建启动时间监听器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 3. 准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 4. 打印Banner
Banner printedBanner = printBanner(environment);
// 5. 创建应用上下文
context = createApplicationContext();
// 6. 刷新上下文(核心)
refreshContext(context);
// 7. 启动后回调
afterRefresh(context, applicationArguments);
stopWatch.stop();
return context;
}
步骤2:环境准备阶段
Environment对象创建与配置加载:
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建Environment对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置Environment(加载配置文件)
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布Environment准备完成事件
listeners.environmentPrepared(bootstrapContext, environment);
// 绑定Environment到Spring
bindToSpringApplication(environment);
return environment;
}
配置文件加载顺序(从低到高):
-
默认属性(通过
SpringApplication.setDefaultProperties()设置) -
@PropertySource注解 -
配置文件(
application.properties/application.yml) -
随机值属性源(
random.*) -
操作系统环境变量
-
Java系统属性(
System.getProperties()) -
JNDI属性
-
Servlet上下文参数
-
Servlet配置参数
-
SPRING_APPLICATION_JSON属性 -
命令行参数(优先级最高)
步骤3:应用上下文创建
根据应用类型创建对应的ApplicationContext:
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
// ApplicationContextFactory.DEFAULT实现
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception ex) {
throw new IllegalStateException("Unable to create ApplicationContext", ex);
}
};
三种容器对比:
| 容器类型 | 适用场景 | 特点 |
|---|---|---|
AnnotationConfigServletWebServerApplicationContext |
Servlet Web应用 | 内嵌Web服务器,支持Servlet API |
AnnotationConfigReactiveWebServerApplicationContext |
响应式Web应用 | 支持响应式编程,无阻塞IO |
AnnotationConfigApplicationContext |
非Web应用 | 轻量级,仅Spring容器功能 |
步骤4:容器刷新 - 核心中的核心
refresh()方法是Spring容器初始化的核心,它触发了Bean的创建、依赖注入、AOP代理等一系列关键操作:
// AbstractApplicationContext.refresh()方法
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. 初始化消息源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 初始化特殊Bean
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 实例化所有单例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
} catch (BeansException ex) {
// 异常处理
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
步骤5:启动后扩展点执行
SpringBoot提供了两个重要的启动后扩展接口:
// ApplicationRunner接口
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
// CommandLineRunner接口
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
执行顺序规则:
-
先执行所有
ApplicationRunner -
再执行所有
CommandLineRunner -
相同接口的实现类可以通过
@Order注解或实现Ordered接口指定顺序
四、关键扩展点解析
1. SpringApplicationRunListener生命周期
启动过程中通过事件机制提供了多个扩展点:
public interface SpringApplicationRunListener {
// 启动开始
default void starting(ConfigurableBootstrapContext bootstrapContext) {}
// 环境准备完成
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {}
// 上下文准备完成
default void contextPrepared(ConfigurableApplicationContext context) {}
// 上下文加载完成
default void contextLoaded(ConfigurableApplicationContext context) {}
// 上下文启动完成
default void started(ConfigurableApplicationContext context) {}
// 应用就绪
default void ready(ConfigurableApplicationContext context) {}
// 启动失败
default void failed(ConfigurableApplicationContext context, Throwable exception) {}
}
默认实现EventPublishingRunListener的事件发布顺序:
| 事件类型 | 触发时机 | 典型用途 |
|---|---|---|
ApplicationStartingEvent |
启动开始时 | 日志初始化 |
ApplicationEnvironmentPreparedEvent |
环境准备完成时 | 配置文件加载 |
ApplicationContextInitializedEvent |
上下文初始化时 | 添加自定义Bean |
ApplicationPreparedEvent |
上下文准备完成时 | 数据源初始化 |
ApplicationStartedEvent |
上下文启动完成时 | 健康检查 |
ApplicationReadyEvent |
应用就绪时 | 服务注册 |
ApplicationFailedEvent |
启动失败时 | 错误处理 |
2. ApplicationContextInitializer应用
这个接口允许我们在Spring容器刷新之前进行自定义初始化:
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
典型应用场景:
-
注册自定义的BeanDefinition
-
激活特定的Profile
-
设置环境变量
-
添加ApplicationListener
示例:自定义Initializer:
public class CustomContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 设置激活的Profile
applicationContext.getEnvironment().addActiveProfile("dev");
// 注册自定义Bean
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) applicationContext;
RootBeanDefinition beanDefinition = new RootBeanDefinition(CustomBean.class);
registry.registerBeanDefinition("customBean", beanDefinition);
}
}
3. 条件注解评估报告
SpringBoot的自动配置基于条件注解,启动时会生成详细的评估报告:
// ConditionEvaluationReportLoggingListener
public class ConditionEvaluationReportLoggingListener
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// 创建条件评估报告
ConditionEvaluationReport report = ConditionEvaluationReport.get(applicationContext.getBeanFactory());
// 注册报告监听器
applicationContext.addApplicationListener(new ConditionEvaluationReportListener(report));
}
}
查看条件评估报告:
# 启动时添加debug参数
java -jar app.jar --debug
# 或者在application.properties中配置
debug=true
五、配置文件解析机制
1. 配置文件加载流程
SpringBoot通过ConfigFileApplicationListener处理配置文件加载:

2. 配置文件优先级详解
从高到低优先级顺序:
// 实际加载顺序(从高优先级到低优先级) 1. 命令行参数 (--server.port=8080) 2. Java系统属性 (System.getProperties()) 3. 操作系统环境变量 4. 项目根目录下的配置文件 5. 项目classpath下的配置文件 6. @Configuration注解类上的@PropertySource 7. SpringApplication.setDefaultProperties()设置的默认属性
特殊位置配置文件:
-
classpath:/(项目资源根目录) -
classpath:/config/(项目config目录) -
file:./(当前目录) -
file:./config/(当前config目录) -
file:./config/*/(当前config的子目录)
3. 多环境配置支持
SpringBoot支持通过Profile实现多环境配置:
yaml
# application.yml
spring:
profiles:
active: dev # 激活dev环境
---
# 开发环境配置
spring:
config:
activate:
on-profile: dev
server:
port: 8080
---
# 生产环境配置
spring:
config:
activate:
on-profile: prod
server:
port: 80
六、内嵌Web服务器启动
1. Tomcat自动配置原理
对于Servlet Web应用,SpringBoot会自动配置内嵌Tomcat:
// ServletWebServerFactoryAutoConfiguration
@AutoConfiguration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
2. Web服务器启动流程
// SpringApplication.refresh()中的onRefresh()方法
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 创建Web服务器
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 获取WebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 创建WebServer
this.webServer = factory.getWebServer(getSelfInitializer());
} else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
} catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
七、启动优化与问题排查
1. 启动性能优化建议
// 1. 延迟初始化配置
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setLazyInitialization(true); // 启用延迟初始化
app.run(args);
}
}
// 2. 排除不必要的自动配置
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
KafkaAutoConfiguration.class
})
public class Application {
// ...
}
2. 常见启动问题排查
问题1:Bean创建失败
bash
# 查看详细的Bean创建日志 logging.level.org.springframework.beans=DEBUG
问题2:自动配置不生效
bash
# 启用条件评估报告 debug=true # 或通过JMX查看 spring.application.admin.enabled=true
问题3:端口被占用
// 自定义端口检测逻辑
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> portCustomizer() {
return factory -> {
int port = SocketUtils.findAvailableTcpPort(8080, 9000);
factory.setPort(port);
};
}
3. 自定义启动脚本示例
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
// 自定义启动配置
app.setBannerMode(Banner.Mode.CONSOLE);
app.setLogStartupInfo(true);
app.setAddCommandLineProperties(true);
// 添加自定义监听器
app.addListeners(new ApplicationStartingListener());
// 运行应用
ConfigurableApplicationContext context = app.run(args);
// 获取启动信息
StartupInfoLogger logger = new StartupInfoLogger(Application.class);
logger.logStarted(getApplicationLog(), context);
}
}
八、总结与最佳实践
核心要点回顾
-
启动流程:构造SpringApplication → 推测应用类型 → 加载扩展组件 → 准备环境 → 创建容器 → 刷新容器 → 执行Runner
-
扩展点:合理使用ApplicationContextInitializer、ApplicationListener、SpringApplicationRunListener进行定制
-
配置优先级:命令行参数 > 系统属性 > 环境变量 > 配置文件
-
容器选择:根据应用类型自动选择Servlet/Reactive/普通容器
最佳实践建议
-
Profile管理:使用Profile分离不同环境配置
-
延迟初始化:大型应用启用延迟初始化提升启动速度
-
条件注解:善用@Conditional系列注解控制Bean加载
-
启动监控:通过Actuator监控启动性能和Bean加载情况
-
自定义Banner:通过banner.txt定制启动Logo
调试技巧
bash
# 1. 查看详细的启动日志 java -jar app.jar --debug # 2. 查看Bean定义 java -jar app.jar --spring.application.admin.enabled=true # 3. 性能分析 java -jar app.jar -Dspring.profiles.active=timing
深入理解SpringBoot启动过程,不仅能帮助我们更好地使用框架,还能在遇到问题时快速定位和解决。掌握这些核心机制,你将能更加游刃有余地进行SpringBoot应用开发和调优。
更多推荐



所有评论(0)