Spring源码解析 - SpringApplication run流程-prepareContext源码分析
prepareContext源码分析
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 1️⃣ 把已准备好的 Environment 设置到 ApplicationContext 中context.setEnvironment(environment);// 2️⃣ 后置处理 ApplicationContext(可被子类覆盖,做额外定制)postProcessApplicationContext(context);// 3️⃣ 执行所有 ApplicationContextInitializer(在 refresh 之前运行)// SpringApplication 初始化setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));的set//钩子函数applyInitializers(context);// 4️⃣ 生命周期事件:contextPrepared —— ApplicationContext 已创建但未 refreshlisteners.contextPrepared(context);// 5️⃣ 关闭早期 BootstrapContext,释放临时资源// 实现bootstrapRegistryInitializers这个钩子注册的bean,将其移动到真正的 BeanFactorybootstrapContext.close(context);// 6️⃣ 如果开启启动信息日志,打印应用名、PID、profile 等if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// 7️⃣ 获取 BeanFactory,准备注册单例 BeanConfigurableListableBeanFactory beanFactory = context.getBeanFactory();// 8️⃣ 把命令行参数包装成 Bean 注册到容器(供开发者使用 @Autowired 注入获取applicationArguments)beanFactory.registerSingleton("springApplicationArguments", applicationArguments);// 9️⃣ 如果前面打印了 Banner,也把 Banner 注册成单例 Beanif (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}// 🔟 根据配置决定是否允许循环依赖if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);}// 1️⃣1️⃣ 根据配置决定是否允许 BeanDefinition 覆盖if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// 1️⃣2️⃣ 如果启用懒加载,添加对应的 BeanFactoryPostProcessorif (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// 1️⃣3️⃣ 添加 PropertySource 排序处理器,保证外部配置优先级正确context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// 1️⃣4️⃣ 获取启动源(主类、@SpringBootApplication、@Import 等)Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");// 1️⃣5️⃣ 真正加载启动源(主类、配置类等)到容器load(context, sources.toArray(new Object[0]));// 1️⃣6️⃣ 生命周期事件:contextLoaded —— BeanDefinition 已加载完毕,等待 refreshlisteners.contextLoaded(context);
}
prepareContext重要流程分析
postProcessApplicationContext分析
postProcessApplicationContext源码解析
① 注入自定义 BeanNameGenerator
if (this.beanNameGenerator != null) {//由于之前context是new AnnotationConfigServletWebServerApplicationContext(),使用空构造//会调用父类的public GenericApplicationContext() {// this.beanFactory = new DefaultListableBeanFactory();//}//通过DefaultListableBeanFactory的super.registerSingleton(beanName, singletonObject);将其注册进单例bean里面,没有bean的创建流程// @Override// public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {// super.registerSingleton(beanName, singletonObject);// updateManualSingletonNames(set -> set.add(beanName), set -> !this.beanDefinitionMap.containsKey(beanName));// clearByTypeCache();// }context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);
}
- 场景:当你显式给
SpringApplication.setBeanNameGenerator(...)
传了自定义实现时。 - 作用:把它注册成 单例 Bean
org.springframework.context.annotation.internalConfigurationBeanNameGenerator
,
之后@Configuration
、@Component
等扫描时就会用它来决定 Bean 名称。
② 注入自定义 ResourceLoader
if (this.resourceLoader != null) {if (context instanceof GenericApplicationContext) {((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);}if (context instanceof DefaultResourceLoader) {((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());}
}
- 场景:
SpringApplication.setResourceLoader(...)
传入过自定义ResourceLoader
(例如读取 jar 外部配置)。 - 作用:
GenericApplicationContext
:替换整个容器的 资源解析器;DefaultResourceLoader
:确保 类加载器 与自定义ResourceLoader
保持一致,避免 classpath 解析错误。
③ 把 Environment 的 ConversionService 塞进 BeanFactory
if (this.addConversionService) {context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}
- 场景:
addConversionService
默认为true
。 - 作用:把 统一类型转换服务 注册进
BeanFactory
,后续:@Value("${port:8080}") int port
@ConfigurationProperties
绑定- 都能用同一套
ConversionService
完成字符串 → 目标类型的转换。
✅ 一句话总结
postProcessApplicationContext
是一个 “启动前置钩子”,
默认实现把 BeanNameGenerator、ResourceLoader、ConversionService 这三个基础设施一次性塞进容器,
确保后续注解扫描、资源加载、属性绑定都能按预期工作。