源码
先看下prepareContext源码,然后让我们逐步分析一下在该阶段 Spring Boot 做了哪些操作。
java
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置环境
context.setEnvironment(environment);
//后置处理
postProcessApplicationContext(context);
//按需添加aot初始化器
addAotGeneratedInitializerIfNecessary(this.initializers);
//执行所有的 ApplicationContextInitializer
applyInitializers(context);
//执行应用上下文准备完成事件
listeners.contextPrepared(context);
//执行启动上下文关闭事件
bootstrapContext.close(context);
//打印启动日志和profile
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 注册相关的单例bean
// Add boot specific singleton beans
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 设置beanFactory 不允许循环引用 和 不允许bean定义覆盖
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));
// 注册bean定义,load内部
if (!AotDetector.useGeneratedArtifacts()) {
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
}
// 执行应用上下文加载完成事件
listeners.contextLoaded(context);
}
设置环境
将 ApplicationServletEnvironment 实例对象设置到应用上下文中
postProcessApplicationContext
应用上下文的后置处理,用于在应用上下文创建之后做一些额外的处理
java
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory()
.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext genericApplicationContext) {
genericApplicationContext.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader defaultResourceLoader) {
defaultResourceLoader.setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
}
从源码看主要做了以下几件事:
-
注册自定义的
bean命名生成器 -
注入自定义的 ResourceLoader,并共用 ResourceLoader 相应的 ClassLoader
-
复用环境中的转换服务,共用一套,避免重复构造
添加 aot 初始化器
这个主要作用是如果启用了aot,则生成对应的aot Initializer,然后将这个aot Initializer 放到 initializers 列表的最前面,优先起作用。aot 是spring应用在构建期预运行一次main,并对一些反射bean的解析提前算好生成对应的Initializer,Initializer里包含了算好的BeanDefinition。这样在触发 initializer 时,就能提前完成bean的注入,而不需要等到执行期的扫描阶段再通过反射方式去完成bean的注入(反射注入bean相对比较耗时),这样启动就很快。
执行所有的 ApplicationContextInitializer
java
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
执行应用上下文准备完成事件
事件类型:ApplicationContextInitializedEvent
java
listeners.contextPrepared(context);
//类:EventPublishingRunListener
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
multicastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
执行启动上下文的close事件
java
bootstrapContext.close(context);
打印启动日志和profile
java
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
注入相关bean、beanFactory定义bean方式设置、应用上下文设置
-
注册 springApplicationArguments 单例bean
-
注册 springBootBanner 单例bean
-
设置是否允许循环引用 allowCircularReferences,默认false
-
设置是否允许bean定义覆盖 allowBeanDefinitionOverriding,默认false
-
如果支持延迟初始化,则设置 LazyInitializationBeanFactoryPostProcessor
-
如果要保活(无存活的非守护线程时,也保持应用存活),设置KeepAlive ApplicationListener
-
添加 PropertySourceOrderingBeanFactoryPostProcessor,用于重排序,将 defaultProperties 属性资源PropertySource 移到最后,优先级最低
注册bean定义
在非aot模式下,完成Sources关联的bean定义的加载,经过这一步 BeanFactory 中就有了'未实例化'的BeanDefinition 集合。关于如何加载可见《Spring Boot 之 BeanDefinitionLoader 详解-CSDN博客》
java
if (!AotDetector.useGeneratedArtifacts()) {
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
}
执行应用上下文上下文加载完成事件
事件类型:ApplicationPreparedEvent
java
listeners.contextLoaded(context);
//类:EventPublishingRunListener
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware contextAware) {
contextAware.setApplicationContext(context);
}
context.addApplicationListener(listener);
}
multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
总结
通过以上分析,我们得到prepareContext 执行流程如下图所示

注:spring boot 版本为3.2.3