当前位置: 首页 > news >正文

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 这三个基础设施一次性塞进容器,
确保后续注解扫描、资源加载、属性绑定都能按预期工作。


http://www.dtcms.com/a/326171.html

相关文章:

  • MD5:理解MD5 / MD5核心特性 / MD5 在前端开发中的常见用途 / 在线生成MD5 / js-md5
  • Linux Docker 运行SQL Server
  • loading效果实现原理
  • Elasticsearch Node.js 客户端的安装
  • 第六十一章:AI 模型的“视频加速术”:Wan视频扩散模型优化
  • 简单清晰的讲解一下RNN神经网络
  • HarmonyOS 开发入门 第一章
  • 力扣面试150题--阶乘后的零,Pow(x,n)直线上最多的点
  • Win10电脑密码忘记如何进入操作系统
  • 基于AS32S601芯片的商业卫星光纤放大器(EDFA)抗单粒子效应解决方案研究
  • 前端组件库双雄对决:Bootstrap vs Element UI 完全指南
  • Speech Databases of Typical Children and Children with SLI 数据集解读
  • 飞轮储能和超级电容综合对比分析
  • LintCode第1181题-二叉树的直径
  • VBA即用型代码手册:计算选择的单词数Count Words in Selection
  • (Arxiv-2025)Phantom-Data:迈向通用的主体一致性视频生成数据集
  • MathType关联Wps实现公式编辑【Tex语法适配】
  • 使用行为树控制机器人(一) —— 节点
  • 【C++语法】输出的设置 iomanip 与 std::ios 中的流操纵符
  • 金蝶云星辰模拟报价功能助力企业快速决策
  • CV 医学影像分类、分割、目标检测,之分类项目拆解
  • Nginx(企业高性能web服务器)
  • 需求优先级如何划分
  • AI炼丹日志-32- memvid 大模型数据库!用视频存储+语义检索实现秒级搜索
  • Pluto Pillow如何靠 “私人定制” 枕头引爆海外市场
  • 学习笔记|decorator 装饰器是什么?
  • 2025-8-11-C++ 学习 暴力枚举(2)
  • 【Linux文件操作】文件操作系统调用
  • [激光原理与应用-231]:光学 - 光学的主要分支、研究对象、应用场合与职业方向(几何光学、物理光学、量子光学、集成光学、非线性光学制造工艺、光学系统设计)
  • 左子树之和