深入理解 Spring ApplicationContext 的 refresh() 方法:容器启动的核心流程
文章目录深入理解 Spring ApplicationContext 的 refresh() 方法容器启动的核心流程一、refresh() 方法概览二、关键步骤详解与调试要点步骤 1prepareRefresh() —— 初始化上下文环境步骤 2obtainFreshBeanFactory() —— 创建 BeanFactory步骤 3prepareBeanFactory(beanFactory) —— 配置标准特性步骤 5invokeBeanFactoryPostProcessors() —— 执行 BFPP步骤 6registerBeanPostProcessors() —— 注册 BPP步骤 11finishBeanFactoryInitialization() —— 初始化单例 Bean步骤 12finishRefresh() —— 发布事件三、代码示例自定义扩展 refresh 流程场景在 Web 容器启动后初始化缓存四、常见问题与解决方案❌ 问题 1Bean 循环依赖导致启动失败❌ 问题 2自定义 BFPP 未按预期执行❌ 问题 3refresh() 被多次调用导致重复初始化五、最佳实践与注意事项✅ 推荐做法⚠️ 注意事项六、总结上周热门博文深入理解 Spring ApplicationContext 的 refresh() 方法容器启动的核心流程在 Spring 应用中ApplicationContext.refresh()是整个 IoC 容器初始化与启动的“总开关”。无论是基于 XML 的ClassPathXmlApplicationContext还是注解驱动的AnnotationConfigApplicationContext亦或是 Spring Boot 中的SpringApplication.run()最终都会调用refresh()方法来完成上下文的构建。本文将系统剖析refresh()方法的 12 个关键步骤结合源码、典型问题与调试技巧帮助开发者深入理解 Spring 容器的启动机制。一、refresh() 方法概览refresh()定义于ConfigurableApplicationContext接口在AbstractApplicationContext中实现。其整体流程如下简化版Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){// 1. 准备刷新prepareRefresh();// 2. 创建并初始化 BeanFactoryConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();// 3. 配置 BeanFactory 的标准特性prepareBeanFactory(beanFactory);try{// 4. 允许子类进一步定制 BeanFactorypostProcessBeanFactory(beanFactory);// 5. 调用所有 BeanFactoryPostProcessorinvokeBeanFactoryPostProcessors(beanFactory);// 6. 注册所有 BeanPostProcessorregisterBeanPostProcessors(beanFactory);// 7. 初始化消息源国际化initMessageSource();// 8. 初始化事件广播器initApplicationEventMulticaster();// 9. 留给子类扩展如 Web 容器初始化 ServletContextonRefresh();// 10. 注册监听器registerListeners();// 11. 实例化所有非懒加载的单例 BeanfinishBeanFactoryInitialization(beanFactory);// 12. 完成刷新发布 ContextRefreshedEventfinishRefresh();}catch(BeansExceptionex){destroyBeans();// 失败时销毁已创建的 BeancancelRefresh(ex);throwex;}}}设计原则模板方法模式refresh()是骨架关键步骤由子类或回调扩展失败安全任何阶段异常都会触发destroyBeans()避免资源泄漏。二、关键步骤详解与调试要点步骤 1prepareRefresh() —— 初始化上下文环境设置启动时间戳标记active true初始化属性源如environment。✅调试建议在此处可检查Environment是否包含预期的配置文件如application-dev.yml。步骤 2obtainFreshBeanFactory() —— 创建 BeanFactory调用refreshBeanFactory()由子类实现如GenericApplicationContext直接返回已有DefaultListableBeanFactory返回一个“新鲜”的BeanFactory。注意FileSystemXmlApplicationContext会在此阶段加载 XML 文件并注册 BeanDefinition。步骤 3prepareBeanFactory(beanFactory) —— 配置标准特性向BeanFactory注册关键组件ClassLoaderBeanExpressionResolver支持 SpELPropertyEditorRegistrar核心 Aware 接口支持如ApplicationContextAwareProcessor忽略某些接口的自动装配如BeanFactoryAware。beanFactory.addBeanPostProcessor(newApplicationContextAwareProcessor(this));beanFactory.ignoreDependencyInterface(EnvironmentAware.class);✅影响此步骤决定了后续Autowired ApplicationContext是否生效。步骤 5invokeBeanFactoryPostProcessors() —— 执行 BFPP这是配置类解析、ConfigurationProperties 绑定、占位符替换的关键阶段。ConfigurationClassPostProcessor解析Configuration、ComponentScan、ImportPropertySourcesPlaceholderConfigurer替换${...}占位符自定义BeanDefinitionRegistryPostProcessor优先执行。⚠️常见问题若自定义BFPP未被调用检查是否正确注册为Component或通过Import引入。步骤 6registerBeanPostProcessors() —— 注册 BPP按优先级排序并注册所有BeanPostProcessor包括AutowiredAnnotationBeanPostProcessor处理AutowiredCommonAnnotationBeanPostProcessor处理PostConstructAnnotationAwareAspectJAutoProxyCreatorAOP 代理入口。重要顺序AOP 代理器必须在普通 BPP 之后注册否则无法拦截初始化后的 Bean。步骤 11finishBeanFactoryInitialization() —— 初始化单例 Bean冻结 BeanDefinition禁止后续修改调用beanFactory.preInstantiateSingletons()按依赖顺序实例化所有非懒加载的 singleton Bean。✅性能瓶颈点大型应用在此阶段耗时最长可通过Lazy延迟初始化非关键 Bean。步骤 12finishRefresh() —— 发布事件启动LifecycleBean如SmartLifecycle.start()发布ContextRefreshedEvent注册 MBeanJMX 支持。// 监听上下文刷新完成ComponentpublicclassStartupListener{EventListenerpublicvoidonContextReady(ContextRefreshedEventevent){System.out.println(ApplicationContext is ready!);}}三、代码示例自定义扩展 refresh 流程场景在 Web 容器启动后初始化缓存publicclassCustomWebApplicationContextextendsAnnotationConfigServletWebServerApplicationContext{OverrideprotectedvoidonRefresh(){super.onRefresh();// 必须调用父类// 此时 ServletContext 已可用initCacheManager();}privatevoidinitCacheManager(){// 从 ApplicationContext 获取 Bean 并初始化CacheServicecachegetBean(CacheService.class);cache.warmUp();}}✅适用场景onRefresh()是 Web 应用集成 Servlet 容器的标准扩展点。四、常见问题与解决方案❌ 问题 1Bean 循环依赖导致启动失败现象BeanCurrentlyInCreationException: ... requested by circular reference原因构造器注入的循环依赖Spring 无法解决原型prototypeBean 的循环依赖。✅解决方案改用 setter 或 field 注入使用Lazy打破依赖链重构设计消除强耦合。ServicepublicclassA{LazyAutowiredprivateBb;// 延迟初始化 B}❌ 问题 2自定义 BFPP 未按预期执行原因BFPP 本身依赖了尚未注册的 Bean未实现PriorityOrdered导致执行顺序靠后。✅修复方式ComponentpublicclassMyBFPPimplementsBeanDefinitionRegistryPostProcessor,PriorityOrdered{OverridepublicintgetOrder(){returnOrdered.HIGHEST_PRECEDENCE;// 最高优先级}OverridepublicvoidpostProcessBeanDefinitionRegistry(BeanDefinitionRegistryregistry){// 在其他 BFPP 之前执行}}❌ 问题 3refresh() 被多次调用导致重复初始化风险refresh()不是幂等的多次调用会抛出IllegalStateException。✅安全做法确保每个ApplicationContext只调用一次refresh()使用ConfigurableApplicationContext.isRunning()判断状态在测试中使用DirtiesContext控制上下文生命周期。五、最佳实践与注意事项✅ 推荐做法避免在 BFPP/BPP 中执行耗时操作会阻塞容器启动关键初始化逻辑放在ContextRefreshedEvent监听器中此时所有 Bean 已就绪使用DependsOn显式控制 Bean 初始化顺序而非依赖隐式顺序生产环境开启spring.main.lazy-initializationtrueSpring Boot 2.2加速启动。⚠️ 注意事项refresh()是同步且阻塞的不要在 Web 请求线程中调用子类重写onRefresh()必须调用super.onRefresh()容器关闭时需调用close()否则单例 Bean 的PreDestroy不会执行。六、总结ApplicationContext.refresh()是 Spring 容器的“生命之源”它以清晰的阶段划分和扩展点设计支撑了从简单配置到复杂企业应用的初始化需求。理解其 12 个步骤的职责与交互不仅能帮助我们高效排查启动问题也为自定义容器行为如多租户、动态模块加载提供了坚实基础。建议结合调试在refresh()各步骤设断点与日志开启logging.level.org.springframeworkDEBUG逐步掌握这一核心机制。在深入原理之后你将能更自信地驾驭 Spring 应用的生命周期。上周热门博文Spring 事务源码导读从 Transactional 到底层数据库提交的完整流程Spring 中不同 Scope 的 Bean 创建机制详解Spring XML 配置中import标签的解析机制与最佳实践Spring XML 解析中的 Document 加载与 EntityResolver 机制详解

相关新闻

FLUX小红书极致真实V2图像生成工具VLOOKUP数据匹配应用

FLUX小红书极致真实V2图像生成工具VLOOKUP数据匹配应用

FLUX小红书极致真实V2图像生成工具VLOOKUP数据匹配应用 如何用Excel函数管理海量AI图像数据 在日常的AI图像生成工作中,最让人头疼的不是技术问题,而是管理那些海量的生成结果。想象一下这样的场景:你已经用FLUX小红书极致真实V2模型生成了上…

2026/7/9 15:32:02 阅读更多 →
Qwen2.5-7B-Instruct部署:Tokenizer分词器配置详解

Qwen2.5-7B-Instruct部署:Tokenizer分词器配置详解

Qwen2.5-7B-Instruct部署:Tokenizer分词器配置详解 1. 引言 如果你正在使用通义千问2.5-7B-Instruct大型语言模型进行二次开发,那么正确配置Tokenizer分词器就是你必须掌握的关键技能。Tokenizer不仅仅是简单的文本切分工具,它直接影响着模…

2026/7/9 16:57:06 阅读更多 →
Wan2.1-umt5自动化办公:Python脚本实现C盘清理与系统优化建议

Wan2.1-umt5自动化办公:Python脚本实现C盘清理与系统优化建议

Wan2.1-umt5自动化办公:Python脚本实现C盘清理与系统优化建议 你是不是也经常被电脑右下角弹出的“C盘空间不足”警告搞得心烦意乱?尤其是办公电脑,用着用着C盘就莫名其妙飘红了,想清理又不知道哪些文件能删,哪些不能…

2026/7/8 8:08:47 阅读更多 →

最新新闻

Claude Artifacts实时协同失效真相,紧急修复手册:3分钟定位context溢出、5分钟重建artifact依赖链

Claude Artifacts实时协同失效真相,紧急修复手册:3分钟定位context溢出、5分钟重建artifact依赖链

更多请点击: https://intelliparadigm.com 第一章:Claude Artifacts实时协同失效的底层归因 Claude Artifacts 的实时协同能力依赖于客户端与 Anthropic 后端服务之间维持长连接的双向事件流(SSE)通道,以及前端对增量…

2026/7/10 14:57:56 阅读更多 →
XposedHider技术深度剖析:如何在Android系统中实现Xposed框架的完美隐身

XposedHider技术深度剖析:如何在Android系统中实现Xposed框架的完美隐身

XposedHider技术深度剖析:如何在Android系统中实现Xposed框架的完美隐身 【免费下载链接】XposedHider 尽可能完美地隐藏 Xposed 项目地址: https://gitcode.com/gh_mirrors/xp/XposedHider 在Android定制化生态中,Xposed框架一直是开发者与高级用…

2026/7/10 14:55:54 阅读更多 →
2026年许可采购趋势:企业应该如何提前布局?

2026年许可采购趋势:企业应该如何提前布局?

如果你还在用三年前的采购逻辑来决策今年的软件预算,那你已经落后了。2026年的软件许可市场正在经历一场深刻的重构。license management市场预计从2025年的14.3亿美元增长至2026年的15.9亿美元,年复合增长率达到11.04%。软件资产管理市场更猛&#xff0…

2026/7/10 14:55:54 阅读更多 →
GPT-6要来了!OpenAI彻底抛弃4T旧底座

GPT-6要来了!OpenAI彻底抛弃4T旧底座

OpenAI紧急提档GPT-6,彻底抛弃4T旧底座?而且,GPT-5.6正式解禁,周四就要上线!Sol、Terra、Luna三款模型全面开放,编码、科研、日常任务全覆盖。已经有早期测试者狂赞Sol模型「永不放弃」,现在&am…

2026/7/10 14:51:53 阅读更多 →
SIGGRAPH 2026 | VeraRetouch:多任务推理式照片修图框架

SIGGRAPH 2026 | VeraRetouch:多任务推理式照片修图框架

作者:vivo BlueImage Lab摘要:我们团队提出了 VeraRetouch,一个轻量、全可微分、可移动端部署的多任务推理式照片修图框架。VeraRetouch 不仅能自动修图,还能听懂用户想要的风格描述,甚至能执行精确的参数式调整。通过…

2026/7/10 14:51:53 阅读更多 →
意大利里米尼环保展新手需知

意大利里米尼环保展新手需知

意大利里米尼环保展参展全指南:背景、优势与参展要求详解 作为环保领域从业者,很多人每年都会关注全球各大国际专业展会,其中意大利里米尼环保展是不少人重点关注的行业标杆展会,不少朋友都在问这个展会到底值不值得去、参展需要满…

2026/7/10 14:49:53 阅读更多 →

日新闻

STM32与LTC1864高精度ADC的SPI通信实现

STM32与LTC1864高精度ADC的SPI通信实现

1. 项目背景与核心需求在工业控制和嵌入式系统开发中,模拟信号与数字系统的无缝集成一直是工程师面临的关键挑战。LTC1864作为一款16位高精度ADC转换器,配合STM32F101ZG这类主流微控制器,能够构建高性能的模拟信号采集系统。这种组合特别适合…

2026/7/10 0:03:07 阅读更多 →
猫抓插件:浏览器资源嗅探与视频下载的终极解决方案

猫抓插件:浏览器资源嗅探与视频下载的终极解决方案

猫抓插件:浏览器资源嗅探与视频下载的终极解决方案 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 还在为网页视频无法下载而烦恼吗&am…

2026/7/10 0:05:09 阅读更多 →
直流有刷电机驱动方案:TC78H653FTG与MKV46F256VLH16应用

直流有刷电机驱动方案:TC78H653FTG与MKV46F256VLH16应用

1. 直流有刷电机驱动方案概述在工业自动化和消费电子领域,直流有刷电机因其结构简单、控制方便、成本低廉等优势,仍然是许多应用场景的首选驱动方案。TC78H653FTG作为东芝推出的新一代H桥驱动器,与MKV46F256VLH16微控制器配合使用&#xff0c…

2026/7/10 0:05:09 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/8 16:14:06 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/9 13:46:46 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/9 21:41:05 阅读更多 →

月新闻