引言
在Spring Boot应用中,SpringApplication.run()方法是整个应用启动的核心入口。理解其内部实现机制,不仅有助于我们更好地掌握Spring Boot的自动配置原理,还能帮助我们在实际开发中进行性能优化和问题排查。本文将深入解析SpringApplication.run()的源码实现,从初始化到上下文刷新的全流程,揭示Spring Boot启动背后的"魔法"。
一、SpringApplication.run()方法概览
1.1 方法定义
在Spring Boot 3.2.x版本中,SpringApplication.run()方法的定义如下:
java
// SpringApplication.java (Spring Boot 3.2.x)
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return new SpringApplication(primarySource).run(args);
}
这个方法看似简单,实际上包含了Spring Boot启动的完整流程。它主要完成以下核心工作:
- 推断应用类型:确定应用是Servlet、Reactive还是None
- 加载并初始化工厂配置 :扫描并加载
META-INF/spring/目录下的工厂配置文件 - 准备运行时环境:包括属性源、配置文件等的加载和初始化
- 创建并配置应用上下文:初始化Spring的应用上下文
- 执行自动配置:根据条件装配需要的Bean
- 启动内嵌服务器:如Tomcat等Web服务器
1.2 启动流程的关键参与者
在整个启动过程中,以下组件扮演着关键角色:
- SpringApplication:启动流程的控制器,协调各个组件的初始化和运行
- Environment:环境抽象,包含配置属性、profiles等信息
- ApplicationContext:Spring容器的核心接口,管理Bean的生命周期
- BeanFactoryPostProcessor:Bean定义的后处理器,允许修改Bean的元数据
- ApplicationRunner/CommandLineRunner:启动后回调接口,允许在应用启动后执行特定逻辑
二、SpringApplication初始化详解
2.1 primarySources:主配置类的旅程
primarySources是SpringApplication构造方法中最重要的参数之一,它代表了应用的主配置类,也就是我们的启动类。例如:
java
public static void main(String[] args) {
SpringApplication.run(NovelApplication.class, args);
}
让我们追踪primarySource的完整旅程:
java
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
java
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 其他初始化
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 其他初始化操作
}
关键说明:
- 唯一性保证 :将传入的主配置类转换为
Set集合,确保唯一性 - 顺序保持 :通过
LinkedHashSet保持原始顺序,这对某些需要顺序保证的配置场景非常重要 - 自动配置基础:作为后续自动配置和组件扫描的基础
- 设计优势 :使用
Set可以避免重复配置类导致的潜在问题,同时LinkedHashSet又能保持初始顺序
2.2 其他关键初始化操作
2.2.1 推断应用类型
java
this.webApplicationType = WebApplicationType.deduceFromClasspath();
判断逻辑:
- 如果存在
DispatcherHandler且不存在DispatcherServlet→REACTIVE - 如果存在Servlet相关类则不是
REACTIVE→SERVLET - 否则 →
NONE
这个判断决定了后续创建的应用上下文类型和内嵌服务器的选择。
2.2.2 推导主应用类
java
this.mainApplicationClass = this.deduceMainApplicationClass();
说明 :SpringApplication会尝试推导主应用类,主要作用于没有明确指定primarySources的时候。推导逻辑基于堆栈跟踪分析,查找包含main方法的类。这个设计体现了Spring Boot的"智能默认值"哲学:尽可能减少必须配置的参数。
2.2.3 资源加载器配置
java
this.resourceLoader = resourceLoader;
说明 :支持自定义ResourceLoader,这在需要特殊资源加载策略的场景下非常有用。如果没有显式指定,Spring Boot会使用默认的DefaultResourceLoader。
三、run()方法执行流程拆解
run()方法的执行流程可分为以下六个关键阶段:
- 准备环境(prepareEnvironment)
- 创建应用上下文(createApplicationContext)
- 准备上下文(prepareContext)
- 刷新上下文(refreshContext)
- 后置处理(afterRefresh)
- 启动完成(事件发布)
让我们看看完整的run()方法实现:
java
public ConfigurableApplicationContext run(String... args) {
Startup startup = SpringApplication.Startup.create();
if (this.registerShutdownHook) {
shutdownHook.enableShutdownHookAddition();
}
// 创建引导上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
Throwable ex;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// Spring Boot启动的时候会打印Spring Boot的标志以及对应的版本
Banner printedBanner = this.printBanner(environment);
// 创建应用上下文
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 准备上下文
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文(关键)
this.refreshContext(context);
// 后置处理
this.afterRefresh(context, applicationArguments);
// 其他
} catch (Throwable ex) {
// 异常处理逻辑
}
return context;
}
3.1 阶段一:准备环境(prepareEnvironment)
环境准备是启动流程的第一步,它负责创建和配置应用的运行环境。
java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext,
ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
this.configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
this.bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(this.getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
3.1.1 getOrCreateEnvironment()
作用:根据应用的类型创建相应的环境实例:
- 非Web应用 :
StandardEnvironment - Servlet Web应用 :
StandardServletEnvironment - Reactive Web应用 :
StandardReactiveWebEnvironment
若已存在环境实例(如自定义环境),则直接复用,保证单例性。
3.1.2 configureEnvironment()
作用:
- 解析命令行参数(
applicationArguments.getSourceArgs())并添加到环境的属性源(PropertySource) - 激活指定的Profiles(如通过
spring.profiles.active配置) - 配置环境的系统属性、环境变量等默认属性源
3.1.3 ConfigurationPropertySources.attach(environment)
核心作用 :将环境中的PropertySource包装为ConfigurationPropertySource,并注册到环境中。
设计意图 :为@ConfigurationProperties注解提供支持。Spring Boot通过ConfigurationPropertySource实现配置属性的类型安全绑定(而非直接解析原始PropertySource)。
3.1.4 DefaultPropertiesPropertySource.moveToEnd(environment)
作用 :将默认属性源移到属性源链的最后,保证用户配置(如application.properties、命令行参数)的优先级高于框架默认值,避免默认值覆盖用户配置。
设计原则:体现了Spring Boot"约定优于配置"的理念,同时确保用户配置始终优先。
3.1.5 bindToSpringApplication(environment)
作用 :将环境中的属性(如spring.main.*配置)绑定到SpringApplication实例的成员变量。
示例 :环境中的spring.main.banner-mode=off会被绑定到SpringApplication的bannerMode属性,控制启动Banner是否显示。
3.2 阶段二:创建应用上下文(createApplicationContext)
根据不同的Web应用类型,Spring Boot会创建不同类型的应用上下文:
java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
抽象逻辑:
java
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
};
说明:
- SERVLET类型 :创建
AnnotationConfigServletWebServerApplicationContext,支持Servlet Web应用 - REACTIVE类型 :创建
AnnotationConfigReactiveWebServerApplicationContext,支持响应式Web应用 - NONE类型 :创建
AnnotationConfigApplicationContext,普通应用上下文
3.3 阶段三:准备应用上下文(prepareContext)
准备上下文阶段是连接环境配置和上下文刷新的桥梁,它完成了大量的初始化工作:
java
private void prepareContext(DefaultBootstrapContext bootstrapContext,
ConfigurableApplicationContext context,
ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments,
Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.addAotGeneratedInitializerIfNecessary(this.initializers);
this.applyInitializers(context);
listeners.contextPrepared(context);
bootstrapContext.close(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
if (!AotDetector.useGeneratedArtifacts()) {
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
}
listeners.contextLoaded(context);
}
3.3.1 绑定环境到上下文
java
context.setEnvironment(environment);
作用:将之前准备好的环境实例(包含属性源、Profiles等)关联到应用上下文。
设计意图 :上下文后续解析Bean定义、处理@Value注解、@ConfigurationProperties时,需通过环境获取配置属性,因此这是上下文与环境的核心绑定步骤。
3.3.2 后置处理应用上下文
java
this.postProcessApplicationContext(context);
作用:对上下文进行定制化后置处理,典型操作包括:
- 设置上下文的
BeanNameGenerator(默认AnnotationBeanNameGenerator,用于生成Bean名称) - 设置上下文的
ResourceLoader(资源加载器,用于读取类路径/文件资源) - 若启用
@EnableAspectJAutoProxy,配置AOP相关的BeanPostProcessor - 为上下文添加
ConversionService(类型转换服务)
3.3.3 应用初始化器
java
this.applyInitializers(context);
作用 :应用所有的ApplicationContextInitializer,对上下文进行进一步的初始化。这些初始化器可以通过META-INF/spring.factories或META-INF/spring/org.springframework.context.ApplicationContextInitializer文件注册。
3.3.4 打印启动日志信息
java
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
说明:
logStartupInfo:控制是否打印启动信息(默认开启),包括Spring Boot版本、应用名称等logStartupProfileInfo:打印当前激活的Profiles(如The following 1 profile is active: "dev")- 作用:提升启动过程的可观测性,方便开发者调试
3.3.5 注册核心单例Bean
java
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
作用 :将ApplicationArguments(应用参数)和Banner(启动横幅)注册为上下文的单例Bean,开发者可通过@Autowired直接注入使用。
3.3.6 配置BeanFactory特性
java
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
说明:
- 允许循环依赖 :
setAllowCircularReferences(默认值由Spring Boot版本决定,2.6+默认关闭),控制是否允许Bean之间的循环依赖(如A依赖B,B依赖A) - 允许Bean定义覆盖 :
setAllowBeanDefinitionOverriding(默认false),控制是否允许后注册的BeanDefinition覆盖之前的同名Bean(如多模块下重复定义Bean)
设计意图:通过配置BeanFactory的核心特性,适配不同的开发场景需求。
3.3.7 启用懒初始化
java
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
说明:
- 懒初始化 :通过
LazyInitializationBeanFactoryPostProcessor实现,所有Bean默认延迟到首次使用时创建(而非上下文刷新时立即创建) - 作用:减少应用启动时间,适用于Bean数量多、启动慢的场景(但需注意懒加载可能导致问题延迟暴露)
3.3.8 注册KeepAlive监听器
java
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
说明:
- KeepAlive:Spring Boot开发环境的热重载/重启支持组件
- 作用:保持应用进程存活,配合DevTools实现代码修改后的自动重启
3.3.9 处理属性源顺序
java
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
说明:
PropertySourceOrderingBeanFactoryPostProcessor:用于调整上下文环境中属性源的优先级顺序- 设计意图 :保证用户配置(如
application.yml)优先级高于框架默认配置,符合Spring Boot"约定优于配置"的原则
3.3.10 加载源配置
java
if (!AotDetector.useGeneratedArtifacts()) {
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
}
作用:加载所有配置源(包括主配置类),将它们注册为Bean定义。这是自动配置和组件扫描的基础。
3.4 阶段四:刷新上下文(refreshContext)
刷新上下文是整个启动流程中最核心、最复杂的阶段。它调用了Spring框架的refresh()方法,完成了Bean的加载、解析、实例化等所有工作。
java
public void refresh() throws BeansException, IllegalStateException {
this.startupShutdownLock.lock();
try {
this.startupShutdownThread = Thread.currentThread();
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (Error | RuntimeException var12) {
Throwable ex = var12;
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
this.destroyBeans();
this.cancelRefresh(ex);
throw ex;
} finally {
contextRefresh.end();
}
} finally {
this.startupShutdownThread = null;
this.startupShutdownLock.unlock();
}
}
refresh()方法包含12个标准步骤(Spring框架核心):
- prepareRefresh:准备刷新上下文
- obtainFreshBeanFactory:获取新的BeanFactory
- prepareBeanFactory:准备BeanFactory
- postProcessBeanFactory:后置处理BeanFactory
- invokeBeanFactoryPostProcessors:执行BeanFactory后置处理器
- registerBeanPostProcessors:注册Bean后置处理器
- initMessageSource:初始化消息源
- initApplicationEventMulticaster:初始化事件广播器
- onRefresh:模板方法(Spring Boot扩展点)
- registerListeners:注册监听器
- finishBeanFactoryInitialization:完成Bean初始化
- finishRefresh:完成刷新
其中,Spring Boot在onRefresh阶段完成了内嵌容器的启动。
3.4.1 refreshContext阶段最关键的三个扩展点
问题 :refreshContext()阶段最关键的三个扩展点是什么?
答案:
- invokeBeanFactoryPostProcessors(执行自动配置)
- onRefresh(内嵌服务器启动)
- finishBeanFactoryInitialization(单例Bean初始化)
这三个步骤分别承担配置解析与自动配置、内嵌服务器启动、单例Bean初始化的核心职责。下面我们逐一解析它们的实现逻辑。
扩展点一:invokeBeanFactoryPostProcessors - 执行自动配置
invokeBeanFactoryPostProcessors(beanFactory)的核心作用是执行所有BeanFactoryPostProcessor接口的实现类。这类处理器可以在Bean定义加载完成后、Bean实例化前修改BeanFactory或Bean定义,Spring Boot的自动配置正是通过这个机制触发的。
1. 框架层核心实现(AbstractApplicationContext)
java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 核心方法:执行BeanFactoryPostProcessor
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// 检测LoadTimeWeaver并注册临时ClassLoader(AOP相关)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors会按优先级顺序执行BeanFactoryPostProcessor:
- 先执行
PriorityOrdered接口的实现类 - 再执行
Ordered接口的实现类 - 最后执行普通的
BeanFactoryPostProcessor
2. Spring Boot自动配置的触发(关键扩展)
Spring Boot的自动配置核心依赖ConfigurationClassPostProcessor(Spring框架内置的BeanFactoryPostProcessor,实现了PriorityOrdered),它会在这一步被执行,具体逻辑:
java
// ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 1. 扫描所有@Configuration类(包括Spring Boot启动类)
List<BeanDefinitionHolder> configCandidates = findCandidateConfigClasses(registry, metadataReaderFactory);
// 2. 解析每个@Configuration类:处理@ComponentScan、@Import、@Bean等注解
for (BeanDefinitionHolder holder : configCandidates) {
ConfigurationClass configClass = new ConfigurationClass(holder.getBeanDefinition(), metadataReaderFactory);
parser.parse(configClass); // 解析配置类
parser.validate();
configurationClasses.put(configClass, configClass);
}
// 3. 处理导入的配置类(关键:Spring Boot的自动配置通过@Import(AutoConfigurationImportSelector.class)触发)
this.reader.loadBeanDefinitions(configurationClasses);
}
关键点:
- AutoConfigurationImportSelector :Spring Boot启动类的
@SpringBootApplication注解包含@EnableAutoConfiguration,而@EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)导入自动配置类 - 自动配置类加载 :
AutoConfigurationImportSelector.selectImports()会读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件(Spring Boot 2.7+),加载所有候选自动配置类(如DataSourceAutoConfiguration、TomcatServletWebServerFactoryAutoConfiguration),并根据条件注解(@ConditionalOnClass、@ConditionalOnMissingBean等)筛选生效的配置类,最终注册为BeanDefinition
总结 :invokeBeanFactoryPostProcessors通过执行ConfigurationClassPostProcessor,完成Spring Boot自动配置类的扫描、解析与注册,为后续Bean实例化奠定基础。
扩展点二:onRefresh - 启动内嵌服务器
onRefresh()是AbstractApplicationContext的模板方法(空实现),子类(如Spring Boot的ServletWebServerApplicationContext)会重写此方法,核心职责是创建并启动内嵌Web服务器(Tomcat/Jetty/Undertow)。
1. 框架层定义(AbstractApplicationContext)
java
protected void onRefresh() throws BeansException {
// 空模板方法,由子类扩展
}
2. Spring Boot的扩展实现(ServletWebServerApplicationContext)
java
@Override
protected void onRefresh() {
super.onRefresh();
try {
// 核心:创建并启动内嵌Web服务器
createWebServer();
} 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) {
// 1. 获取WebServerFactory(由自动配置类提供,如TomcatServletWebServerFactory)
ServletWebServerFactory factory = getWebServerFactory();
// 2. 创建WebServer(如TomcatWebServer)
this.webServer = factory.getWebServer(getSelfInitializer());
// 3. 注册ApplicationContext到ServletContext(供ServletContextAware组件使用)
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
} catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
说明:
- WebServerFactory获取 :
getWebServerFactory()会从BeanFactory中获取ServletWebServerFactory类型的Bean(由TomcatServletWebServerFactoryAutoConfiguration等自动配置类注册) - WebServer创建 :
factory.getWebServer()会根据工厂类型创建对应的服务器实例(如TomcatWebServer会初始化Tomcat的Tomcat对象,配置连接器、引擎等) - 服务器启动 :
WebServerStartStopLifecycle会在上下文刷新完成后触发webServer.start(),启动内嵌服务器(绑定端口、监听请求)
总结 :Spring Boot通过重写onRefresh()方法,在上下文刷新阶段创建并启动内嵌Web服务器,实现"一键启动Web应用"的特性。
扩展点三:finishBeanFactoryInitialization - 初始化所有单例Bean
finishBeanFactoryInitialization(beanFactory)是refresh()的核心步骤,负责初始化所有非懒加载的单例Bean(实例化、属性填充、初始化方法调用),Spring Boot自动配置的Bean(如DataSource、JdbcTemplate)都会在此阶段完成初始化。
1. 框架层核心实现(AbstractApplicationContext)
java
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 1. 初始化ConversionService(类型转换服务)
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 2. 注册嵌入式值解析器(处理@Value中的${}占位符)
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// 3. 初始化LoadTimeWeaverAwareBean(AOP织入相关)
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 4. 冻结Bean定义(禁止修改BeanDefinition)
beanFactory.freezeConfiguration();
// 5. 核心:初始化所有非懒加载的单例Bean
beanFactory.preInstantiateSingletons();
}
2. 单例Bean初始化的核心逻辑(DefaultListableBeanFactory.preInstantiateSingletons)
java
@Override
public void preInstantiateSingletons() throws BeansException {
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// 遍历所有BeanDefinition名称
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 跳过抽象Bean、非单例Bean、懒加载Bean
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 处理FactoryBean:先初始化FactoryBean本身,再通过getObject()获取实际Bean
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
} else {
// 核心:初始化普通Bean
getBean(beanName);
}
}
}
// 触发SmartInitializingSingleton的afterSingletonsInstantiated方法
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
smartSingleton.afterSingletonsInstantiated();
}
}
}
3. Bean初始化的完整流程(getBean(beanName)的底层逻辑)
当调用getBean(beanName)时,会触发Bean的完整生命周期:
- 实例化 :通过反射或工厂方法创建Bean实例(
AbstractAutowireCapableBeanFactory.createBeanInstance) - 属性填充 :将依赖的Bean(如
@Autowired标注的属性)注入到当前Bean(populateBean) - 初始化 :
- 执行
BeanNameAware、ApplicationContextAware等Aware接口的方法 - 执行
BeanPostProcessor.postProcessBeforeInitialization(如AutowiredAnnotationBeanPostProcessor处理@Value) - 执行
@PostConstruct注解的方法或init-method配置的初始化方法(invokeInitMethods) - 执行
BeanPostProcessor.postProcessAfterInitialization(如AOP的动态代理创建)
- 执行
- 注册DisposableBean :若Bean实现
DisposableBean或配置destroy-method,注册销毁回调
Spring Boot的特殊处理 :自动配置的Bean(如DataSource)会在此阶段完成初始化。DataSourceAutoConfiguration注册的DataSource BeanDefinition会被实例化,通过@ConfigurationProperties绑定application.properties中的数据库配置(如spring.datasource.url),最终生成可用的DataSource实例。
总结 :finishBeanFactoryInitialization通过preInstantiateSingletons()完成所有非懒加载单例Bean的初始化,是Spring容器"依赖注入"和"Bean实例化"的最终落地步骤。
3.5 阶段五:后置处理(afterRefresh)
在上下文刷新完成后,Spring Boot会执行后置处理:
java
private void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
callRunners(context, args);
}
作用 :调用所有实现了ApplicationRunner或CommandLineRunner接口的Bean,执行其run()方法。这些Runner允许开发者在应用完全启动后执行特定的初始化逻辑。
3.6 阶段六:启动完成(事件发布)
在应用上下文刷新和后置处理完成后,Spring Boot会发布以下事件:
- ApplicationStartedEvent:应用已启动(上下文已刷新)
- ApplicationReadyEvent:应用已就绪(所有Runner已执行)
这些事件可以被ApplicationListener监听,用于执行启动后的自定义逻辑。
四、invokeBeanFactoryPostProcessors与AutoConfigurationImportSelector的深度联动
要理解invokeBeanFactoryPostProcessors与AutoConfigurationImportSelector的深度联动,需从触发链路、注解解析、自动配置类加载、BeanDefinition注册四个维度拆解,明确两者如何协作完成Spring Boot的自动配置核心逻辑。
4.1 联动起点:invokeBeanFactoryPostProcessors触发ConfigurationClassPostProcessor执行
invokeBeanFactoryPostProcessors是整个联动的入口,其核心是通过PostProcessorRegistrationDelegate按优先级执行BeanFactoryPostProcessor:
- 优先级触发规则 :
ConfigurationClassPostProcessor实现了PriorityOrdered接口,因此会被优先执行(这是联动的前提,保证自动配置逻辑在其他BeanFactoryPostProcessor前完成) - 执行入口 :
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors会调用ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry方法,进而触发其核心逻辑processConfigBeanDefinitions
4.2 关键桥梁:ConfigurationClassPostProcessor解析@EnableAutoConfiguration与@Import
ConfigurationClassPostProcessor的processConfigBeanDefinitions方法是连接两者的核心桥梁,它在解析Spring Boot启动类时,会触发对AutoConfigurationImportSelector的调用。
4.2.1 扫描启动类(@SpringBootApplication)
Spring Boot启动类标注的@SpringBootApplication是一个复合注解,包含:
java
@SpringBootConfiguration // 本质是@Configuration
@EnableAutoConfiguration // 关键:触发自动配置
@ComponentScan // 组件扫描
ConfigurationClassPostProcessor会将启动类识别为@Configuration类(候选配置类),进入解析流程。
4.2.2 解析@EnableAutoConfiguration注解
@EnableAutoConfiguration的核心源码:
java
@Import(AutoConfigurationImportSelector.class) // 导入AutoConfigurationImportSelector
public @interface EnableAutoConfiguration { ... }
ConfigurationClassPostProcessor在解析@EnableAutoConfiguration时,会处理其中的@Import注解:
当遇到@Import导入的是ImportSelector类型(AutoConfigurationImportSelector实现了ImportSelector),会调用其selectImports方法,获取需要导入的配置类名称。
4.3 核心协作:AutoConfigurationImportSelector加载并筛选自动配置类
ConfigurationClassPostProcessor调用AutoConfigurationImportSelector.selectImports,这是联动的核心环节,AutoConfigurationImportSelector在此完成自动配置类的加载与筛选。
4.3.1 加载候选自动配置类
selectImports的核心逻辑依赖AutoConfigurationImportSelector.AutoConfigurationGroup(内部类)的process方法:
java
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 1. 读取候选自动配置类列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 2. 去重、排序、应用排除规则(@SpringBootApplication(exclude = ...))
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
configurations.removeAll(exclusions);
// 3. 条件筛选:根据@Conditional注解判断配置类是否生效
configurations = getConfigurationClassFilter().filter(configurations);
// 4. 记录自动配置报告(供启动日志输出)
fireAutoConfigurationImportEvents(configurations, exclusions);
this.entries.putIfAbsent(annotationMetadata, new Entry(configurations, exclusions));
}
关键点:
- getCandidateConfigurations :通过
SpringFactoriesLoader读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件(Spring Boot 2.7+),获取所有候选自动配置类(如DataSourceAutoConfiguration、WebMvcAutoConfiguration) - 条件筛选 :通过
ConfigurationClassFilter(默认是OnClassCondition)结合@ConditionalOnClass、@ConditionalOnMissingBean等注解,筛选出当前环境下生效的自动配置类(例如:若项目中没有Tomcat依赖,TomcatServletWebServerFactoryAutoConfiguration会被过滤)
4.3.2 返回生效配置类名称
AutoConfigurationImportSelector最终将筛选后的自动配置类名称返回给ConfigurationClassPostProcessor。
4.4 收尾联动:ConfigurationClassPostProcessor注册自动配置类为BeanDefinition
ConfigurationClassPostProcessor拿到AutoConfigurationImportSelector返回的生效配置类名称后,会继续完成:
- 解析自动配置类 :将每个自动配置类(如
DataSourceAutoConfiguration)作为@Configuration类解析,处理其内部的@Bean、@Conditional等注解 - 注册BeanDefinition :通过
ConfigurationClassBeanDefinitionReader将自动配置类中的Bean定义(如DataSource、JdbcTemplate)注册到BeanFactory中
至此,invokeBeanFactoryPostProcessors通过触发ConfigurationClassPostProcessor,联动AutoConfigurationImportSelector完成了自动配置类的加载、筛选、解析与注册,为后续finishBeanFactoryInitialization阶段的Bean实例化奠定基础。
4.5 联动逻辑总结(时序图简化)
java
invokeBeanFactoryPostProcessors
↓ 触发PriorityOrdered的BeanFactoryPostProcessor
ConfigurationClassPostProcessor.processConfigBeanDefinitions
↓ 解析启动类的@SpringBootApplication
↓ 解析@EnableAutoConfiguration中的@Import(AutoConfigurationImportSelector)
AutoConfigurationImportSelector.selectImports
↓ 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
↓ 条件筛选生效的自动配置类
↓ 返回生效配置类列表
ConfigurationClassPostProcessor注册自动配置类为BeanDefinition
4.6 关键设计亮点
- 分层解耦 :
invokeBeanFactoryPostProcessors负责触发后置处理器,ConfigurationClassPostProcessor负责配置类解析,AutoConfigurationImportSelector专注于自动配置类加载------职责分离,符合单一原则 - 扩展性 :通过
ImportSelector接口,Spring Boot将自动配置逻辑与配置类解析逻辑解耦,开发者可自定义ImportSelector扩展自动配置 - 条件控制 :
AutoConfigurationImportSelector结合条件注解实现"按需配置",体现Spring Boot"约定优于配置"的核心思想
正是这种精准的联动,使得Spring Boot能自动识别环境、加载适配的配置类,无需开发者手动编写大量配置。
五、Spring Boot 3.2.x中的优化
在Spring Boot 3.2.x版本中,对启动流程进行了以下优化:
5.1 延迟初始化优化
对BeanDefinition的加载策略进行了调整,减少了启动时的内存占用。通过优化Bean定义的加载时机和方式,Spring Boot 3.2.x能够更高效地管理内存,特别是在大型应用中效果显著。
5.2 环境准备阶段重构
将环境变量的处理提前到上下文创建之前,提高了启动效率。这种重构使得环境配置的解析和验证能够更早完成,减少了后续阶段的等待时间。
5.3 其他性能优化
- 启动性能监控 :引入了
Startup类,提供更细粒度的启动性能监控 - AOT支持增强:对AOT(Ahead-Of-Time)编译的支持更加完善,进一步提升启动速度
- 资源加载优化:优化了资源文件的加载策略,减少了I/O操作