前言
在上一篇中,我们已经成功搭建了Spring Boot源码研究环境。
现在,让我们深入Spring Boot的核心------启动过程。
当你运行一个Spring Boot应用的main方法时,背后究竟发生了什么?
本文将带你从SpringApplication.run()开始,一步步揭开Spring Boot启动的神秘面纱。
在正式开始介绍之前,先用形象的方式类比SpringApplication这个类用途。
0、把SpringApplication想象成**"汽车制造工厂"**
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
这就像在说:"我们要建造一个汽车制造工厂,这是我们的原料供应商 (resourceLoader)和核心设计图纸(primarySources)"
🔧 一步步拆解这个"汽车工厂"的建造过程:
1. 接收核心设计图纸
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
通俗解释:
工厂收到你给的核心设计图纸(就是你的@SpringBootApplication主类)。比如你传入了DemoApplication.class,工厂就知道:"哦,我要按照这个设计来造车!"
2. 判断要造什么类型的车
this.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());
通俗解释:
工厂自动检查你的"零件仓库"(类路径),判断你要造什么车:
- 发现有Servlet零件 → 造传统Web汽车(SERVLET)
- 发现有WebFlux零件 → 造新能源响应式汽车(REACTIVE)
- 什么Web零件都没有 → 造普通家用轿车(NONE)
3. 招聘第一批基础工人
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
通俗解释:
工厂先招聘地基施工队(BootstrapRegistryInitializer),这些工人在工厂刚建好时就进场,负责打地基、铺管线等最基础的工作。
4. 招聘车间主任和质检员
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
通俗解释:
接着招聘车间主任(ApplicationContextInitializer),他们负责在各个车间(ApplicationContext)正式开工前,检查设备、调整生产线布局。
5. 安装监控摄像头和警报器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
通俗解释:
安装监控系统(ApplicationListener),这些"耳朵"会监听工厂里发生的各种事件:机器启动、零件到位、故障报警等。
6. 确定总设计师办公室
this.mainApplicationClass = deduceMainApplicationClass();
通俗解释:
自动找到总设计师的办公室(主应用类),这样工厂有任何问题都知道该找谁汇报。
🚗 完整造车流程比喻:
想象一下整个Spring Boot启动就像造一辆汽车:
- 设计阶段(SpringApplication构造器)
-
- 拿到设计图纸(
primarySources) - 决定造什么车(
WebApplicationType) - 招聘各种工人(各种
Initializer和Listener)
- 拿到设计图纸(
- 生产线准备(run()方法开始)
-
- 地基工人进场(
BootstrapRegistryInitializer) - 车间主任检查设备(
ApplicationContextInitializer) - 启动监控系统(
ApplicationListener)
- 地基工人进场(
- 正式生产(refresh()方法)
-
- 零件生产线运转(Bean创建)
- 组装整车(Bean依赖注入)
- 质量检测(Bean后置处理)
- 出厂上路(启动完成)
-
- 汽车可以开了(应用可以接收请求)
- 监控系统持续工作(事件监听)
🎯 给新手的核心理解要点:
为什么要有这么多"工人"?
- 分工明确:每个工人只负责自己的专业领域
- 可扩展性:你可以自己招聘新工人(自定义Initializer/Listener)
- 生命周期管理:工人们按照固定顺序工作,不会乱套
这个构造器的作用总结:
// 用一句话总结这个构造器:
"收集所有必要的工具和工人,为后续的汽车制造做好准备"
下一步会发生什么:
构造器只是准备工作 ,真正的"造车"是在run()方法中:
// 准备工作完成,开始造车!
SpringApplication.run(DemoApplication.class, args);
💡 形象记忆技巧:
把SpringApplication想象成:
- resourceLoader = 原料供应商
- primarySources = 核心设计图纸
- BootstrapRegistryInitializer = 地基施工队
- ApplicationContextInitializer = 车间主任
- ApplicationListener = 监控摄像头
- mainApplicationClass = 总设计师办公室
这样下次看到这段代码,你就能立即在脑海中构建出这个"汽车工厂"的生动画面了!
理解了这个比喻,后续学习run()方法时就会轻松很多,因为那只是按部就班地执行这个"造车流程"而已。
1. SpringApplication初始化:启动的起点
1.1 入口点分析
让我们从最简单的Spring Boot应用开始:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
关键源码位置: spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java
接下来用一个非常形象的比喻来理解SpringApplication的作用和执行流程。
1.2 构造器初始化过程
// SpringApplication构造器核心逻辑
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 关键步骤1:推断Web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 关键步骤2:加载应用上下文初始化器
setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 关键步骤3:加载应用事件监听器
setListeners(getSpringFactoriesInstances(ApplicationListener.class));
// 关键步骤4:推断主应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.3 Web应用类型推断
// WebApplicationType.deduceFromClasspath() 源码分析
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, 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应用
}
调试技巧: 在deduceFromClasspath()方法设置断点,观察类路径检测逻辑。
2. run方法执行流程:启动的核心
2.1 run方法整体架构
public ConfigurableApplicationContext run(String... args) {
// 1. 启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 创建引导上下文和应用上下文
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 3. 获取SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
// 4. 发布ApplicationStartingEvent事件
listeners.starting();
try {
// 5. 准备环境
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 6. 打印Banner
Banner printedBanner = printBanner(environment);
// 7. 创建应用上下文
context = createApplicationContext();
// 8. 准备应用上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 9. 刷新上下文(Spring核心流程)
refreshContext(context);
// 10. 后置处理
afterRefresh(context, applicationArguments);
// 11. 停止计时器
stopWatch.stop();
// 12. 发布启动完成事件
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
// 13. 执行Runner
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
2.2 环境准备阶段
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建和配置环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布EnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
// 绑定环境到SpringApplication
bindToSpringApplication(environment);
// 转换环境(如果需要)
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 配置PropertySources
ConfigurationPropertySources.attach(environment);
return environment;
}
2.3 应用上下文创建
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据Web应用类型选择不同的上下文实现
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, " +
"please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
3. 上下文刷新:Spring核心流程
3.1 refreshContext核心流程
// 这是Spring框架的核心方法,Spring Boot进行了封装
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// 不在允许的环境中
}
}
}
// 实际调用Spring的refresh方法
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
3.2 Spring Framework的refresh方法
// 在AbstractApplicationContext中定义,包含12个关键步骤
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. 调用BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册BeanPostProcessors
registerBeanPostProcessors(beanFactory);
// 7. 初始化MessageSource
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 初始化特殊Bean(由子类实现)
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 完成BeanFactory初始化,实例化所有单例Bean
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新过程,发布ContextRefreshedEvent事件
finishRefresh();
} catch (BeansException ex) {
// 清理资源
destroyBeans();
cancelRefresh(ex);
throw ex;
} finally {
resetCommonCaches();
}
}
}
3.3 Spring Boot的onRefresh扩展
// 在SpringApplication中,onRefresh方法被重写以支持Web服务器启动
protected void onRefresh(ApplicationContext context) {
// 调用父类方法
super.onRefresh(context);
// Spring Boot特有的:创建Web服务器
if (context instanceof ConfigurableWebServerApplicationContext) {
((ConfigurableWebServerApplicationContext) context)
.setServerNamespace(this.serverNamespace);
}
}
4. 自动配置机制:Spring Boot的魔法核心
4.1 @SpringBootApplication注解解析
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
public @interface SpringBootApplication {
// 省略属性定义
}
4.2 @EnableAutoConfiguration核心机制
@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 {};
}
4.3 AutoConfigurationImportSelector工作流程
// 这是自动配置的核心类
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 1. 获取自动配置条目
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 2. 检查自动配置是否启用
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 3. 获取注解属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 4. 获取候选配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 5. 移除重复配置
configurations = removeDuplicates(configurations);
// 6. 根据exclude属性排除配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 7. 应用过滤条件
configurations = getConfigurationClassFilter().filter(configurations);
// 8. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
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. " +
"If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
}
5. Web服务器启动:内嵌容器的奥秘
5.1 Servlet Web服务器启动
// 在ServletWebServerApplicationContext中
@Override
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) {
// 从BeanFactory获取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();
}
5.2 Tomcat服务器创建过程
// 在TomcatServletWebServerFactory中
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
// 1. 创建Tomcat实例
Tomcat tomcat = new Tomcat();
// 2. 配置基础目录
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 3. 创建Connector
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
// 4. 创建Engine和Host
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
// 5. 准备Context
prepareContext(tomcat.getHost(), initializers);
// 6. 返回自定义的TomcatWebServer
return getTomcatWebServer(tomcat);
}
6. 启动扩展点:自定义启动行为
6.1 ApplicationRunner vs CommandLineRunner
// ApplicationRunner示例
@Component
@Order(1) // 指定执行顺序
public class DemoApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner执行,参数: " + Arrays.toString(args.getSourceArgs()));
// 应用启动后需要执行的逻辑
}
}
// CommandLineRunner示例
@Component
@Order(2)
public class DemoCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner执行,参数: " + Arrays.toString(args));
// 应用启动后需要执行的逻辑
}
}
6.2 应用事件监听机制
// 监听应用启动事件
@Component
public class ApplicationStartupListener implements ApplicationListener<ApplicationStartedEvent> {
private static final Logger logger = LoggerFactory.getLogger(ApplicationStartupListener.class);
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
logger.info("应用启动完成,开始执行初始化任务...");
// 执行自定义初始化逻辑
performInitialization();
}
private void performInitialization() {
// 初始化缓存、连接池等
}
}
7. 调试与实验:验证启动过程
7.1 创建调试配置
在IDEA中创建调试配置,添加以下VM参数:
-Ddebug=true -Dspring.output.ansi.enabled=ALWAYS
7.2 关键断点设置建议
设置断点观察启动流程:
SpringApplication构造器SpringApplication.run()方法入口prepareEnvironment()方法createApplicationContext()方法refreshContext()方法onRefresh()方法(Web服务器启动)
7.3 启动日志分析
启用debug日志观察启动细节:
# application.properties
logging.level.org.springframework.boot=DEBUG
logging.level.org.springframework.context=DEBUG
8. 启动过程总结与核心流程图
8.1 启动过程核心步骤

8.2 关键设计模式应用
- 模板方法模式 :
AbstractApplicationContext.refresh()定义了算法骨架 - 观察者模式:Spring事件机制
- 工厂模式 :
ApplicationContext创建 - 策略模式:不同的Web应用类型处理
- 责任链模式 :
BeanPostProcessor调用链
结语
通过本文的深入分析,我们揭示了Spring Boot启动过程的完整流程。从SpringApplication初始化到Web服务器启动,每一个步骤都体现了Spring Boot"约定大于配置"的设计哲学。
关键收获:
- Spring Boot启动是Spring Framework生命周期与Boot特有扩展的结合
- 自动配置通过
SpringFactoriesLoader机制实现 - Web服务器启动在
onRefresh阶段触发 - 事件机制为启动过程提供了丰富的扩展点
下篇预告: 在下一篇文章中,我们将深入Spring Boot的自动配置机制,解析@Conditional注解体系,并学习如何编写自定义的Starter。
思考题:
- 如果在启动过程中需要读取配置文件中的自定义配置,应该在哪个阶段进行?
- 如何在不修改源码的情况下,在Bean创建前后插入自定义逻辑?
- Spring Boot如何支持多种内嵌Web服务器(Tomcat、Jetty、Undertow)的自动切换?
欢迎在评论区分享你的理解和遇到的问题!
