☰
spring 的 核心 refresh() 方法阅读技巧
2026/10/21 11:03:33 网站建设 项目流程

Spring 的refresh()方法是理解整个 IoC 容器核心逻辑的最佳入口。这个方法就像容器的“启动总纲”,定义了从加载配置到创建所有单例 Bean 的完整流程。下面我帮你把它拆解成几个易于理解的阶段,并告诉你每一步该看什么、怎么调试。

📍 一、先找到refresh()方法

  • 所在类:org.springframework.context.support.AbstractApplicationContext

  • 版本:以你正在阅读的 5.3.x 为例

  • 定位技巧:在 IDEA 中双击Shift,输入AbstractApplicationContext.refresh直接跳转

这个方法是public void refresh() throws BeansException, IllegalStateException,它的代码结构非常清晰,由一系列具有明确职责的子方法组成。


🔍 二、宏观俯瞰:refresh() 的整体骨架

先看一眼方法的整体结构,大概有十几个步骤,但核心可以归纳为三大阶段:

  1. 准备阶段:为容器启动做准备(环境、监听器等)

  2. BeanFactory 创建与配置阶段:加载配置、注册 BeanPostProcessor、执行 BeanFactoryPostProcessor

  3. 单例 Bean 实例化阶段:初始化所有剩余的单例 Bean(非懒加载)

对应的代码骨架(简化后):

public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 准备上下文 prepareRefresh(); // 2. 获取新的 BeanFactory(通常是从新加载的配置中创建) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. 对 BeanFactory 进行预填充(如设置类加载器、添加后置处理器等) prepareBeanFactory(beanFactory); try { // 4. 允许子类对 BeanFactory 进行后置处理(模板方法) postProcessBeanFactory(beanFactory); // 5. 调用 BeanFactoryPostProcessor(重要!) invokeBeanFactoryPostProcessors(beanFactory); // 6. 注册 BeanPostProcessor(重要!) registerBeanPostProcessors(beanFactory); // 7. 初始化消息源(国际化) initMessageSource(); // 8. 初始化事件广播器 initApplicationEventMulticaster(); // 9. 模板方法:留给子类刷新特定 bean onRefresh(); // 10. 注册监听器 registerListeners(); // 11. **核心:实例化所有非懒加载的单例 Bean** finishBeanFactoryInitialization(beanFactory); // 12. 最后一步:发布容器刷新完成事件 finishRefresh(); } catch (BeansException ex) { // 异常处理:销毁已创建的 bean destroyBeans(); cancelRefresh(ex); throw ex; } finally { // 重置公共缓存 resetCommonCaches(); } } }

🧭 三、关键步骤拆解(建议打断点阅读)

你可以从第 1 步开始逐行 Debug ,或者直接跳到最核心的finishBeanFactoryInitialization。但为了更好地理解上下文,建议按顺序跟踪。

1️⃣prepareRefresh()

  • 做什么:设置启动时间、激活状态、初始化属性源、验证必要属性。

  • 关注点:initPropertySources()是一个模板方法,留给子类扩展(例如 Web 环境会设置 servlet 相关属性)。

  • 断点:可以放在方法内部,观察environment的变化。

2️⃣obtainFreshBeanFactory()

  • 做什么:这是创建或刷新 BeanFactory 的地方。

  • 调用链:refreshBeanFactory()→ 如果是AbstractRefreshableApplicationContext(如 XML 或注解配置),会销毁原有的 BeanFactory,重新加载配置,创建新的DefaultListableBeanFactory,并读取所有 Bean 定义(loadBeanDefinitions)。

  • 关注点:从这里开始,容器拥有了所有 Bean 的元信息(BeanDefinition)。

  • 断点:在loadBeanDefinitions方法中,可以观察 XML 或注解是如何被解析成BeanDefinition的。

3️⃣prepareBeanFactory(beanFactory)

  • 做什么:为 BeanFactory 配置标准特性,如:

    • 设置类加载器

    • 添加ApplicationContextAwareProcessor(处理 Aware 接口)

    • 注册一些特殊的单例 Bean(如environment、systemProperties等)

  • 关注点:这里注册的BeanPostProcessor会在后续对所有 Bean 生效。

4️⃣postProcessBeanFactory(beanFactory)

  • 做什么:空方法,留给子类覆盖(例如在 Web 环境中注册 Web 相关的 Scope 或 ServletContextAwareProcessor)。

  • 断点:如果你在 Web 环境下调试,可以关注子类的实现。

5️⃣invokeBeanFactoryPostProcessors(beanFactory)⭐️

  • 做什么:调用所有注册的BeanFactoryPostProcessor(包括BeanDefinitionRegistryPostProcessor)。

  • 谁在这里执行:例如ConfigurationClassPostProcessor(处理@Configuration类)、PropertySourcesPlaceholderConfigurer(解析占位符${...})。

  • 效果:此时可以对尚未实例化的BeanDefinition进行修改或注册新 Bean。

  • 断点:观察BeanFactoryPostProcessor的执行顺序,以及BeanDefinition的变化。

6️⃣registerBeanPostProcessors(beanFactory)⭐️

  • 做什么:将所有实现了BeanPostProcessor接口的 Bean 注册到 BeanFactory 的beanPostProcessors列表中。注意:这里只是注册,不会调用它们的方法。

  • 顺序:先注册实现了PriorityOrdered的,再是Ordered,最后是普通的。

  • 断点:可以查看beanPostProcessors列表的内容。

7️⃣initMessageSource()

  • 做什么:初始化国际化消息源。

  • 关注点:如果容器中没有名为messageSource的 Bean,会注册一个DelegatingMessageSource作为空实现。

8️⃣initApplicationEventMulticaster()

  • 做什么:初始化事件广播器。默认是SimpleApplicationEventMulticaster。

  • 关注点:这里决定了事件发布的方式(同步/异步)。

9️⃣onRefresh()

  • 做什么:模板方法,留给子类初始化特定的 Bean(例如 Web 容器中的ThemeSource或内嵌 Web 服务器)。

  • 断点:如果你在 Spring Boot 中调试,这里会触发ServletWebServerApplicationContext的onRefresh(),从而启动内嵌 Tomcat。

🔟registerListeners()

  • 做什么:将容器中所有实现了ApplicationListener的 Bean 注册到事件广播器,并可能发布早期事件。

  • 关注点:可以观察监听器是如何被添加的。

1️⃣1️⃣finishBeanFactoryInitialization(beanFactory)⭐️⭐️⭐️

  • 做什么:核心中的核心——实例化所有剩余的非懒加载单例 Bean。

  • 如何实现:调用beanFactory.preInstantiateSingletons(),该方法会遍历所有BeanDefinition,依次调用getBean()(最终触发doCreateBean)。

  • 关键子步骤:

    • 处理 FactoryBean(加&前缀获取 FactoryBean 本身)

    • 解决循环依赖(三级缓存登场)

    • 调用 BeanPostProcessor 的postProcessBeforeInitialization和postProcessAfterInitialization

    • 执行InitializingBean.afterPropertiesSet()和自定义 init-method

  • 断点:这是最重要的断点位置。可以从getBean开始,一路跟踪到doCreateBean,观察 Bean 的完整生命周期。

1️⃣2️⃣finishRefresh()

  • 做什么:清理资源缓存、初始化生命周期处理器、发布ContextRefreshedEvent事件。

  • 关注点:这里触发了实现了SmartLifecycle的 Bean 的启动。


🧪 四、推荐调试路线

  1. 起点:在你的测试类中调用new AnnotationConfigApplicationContext(MyConfig.class)后,立即在refresh()方法第一行打上断点。

  2. 逐步前进:用 F8(Step Over)逐个步骤执行,观察每个方法调用前后的变化。

  3. 深入核心:当执行到finishBeanFactoryInitialization时,用 F7(Step Into)进入该方法,再进入preInstantiateSingletons(),然后观察getBean的调用。

  4. 观察循环依赖:如果你的测试中有循环依赖的场景,可以重点关注三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)的变化。

  5. 观察后置处理器:在doCreateBean中,留意applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization的调用。


🧠 五、需要理解的设计思想

  • 模板方法模式:refresh()本身就是一个模板方法,定义了大流程,一些步骤(如postProcessBeanFactory、onRefresh)留给子类实现,以适应不同环境。

  • 工厂方法模式:obtainFreshBeanFactory()通过refreshBeanFactory()创建具体的 BeanFactory 实现。

  • 观察者模式:通过事件发布/监听机制,实现容器内各组件之间的解耦。

  • 策略模式:BeanFactoryPostProcessor和BeanPostProcessor允许用户插入自定义逻辑,改变 Bean 的定义或实例化过程。

📚 六、阅读过程中可能遇到的难点

难点解释
循环依赖解决三级缓存singletonFactories是关键,理解“提前暴露”的含义。建议结合 debug 看缓存变化。
BeanPostProcessor 的执行时机区分两类:在registerBeanPostProcessors中注册,在 Bean 实例化前后执行。
FactoryBean 和普通 Bean注意&前缀,理解getObject()的调用时机。
AOP 代理的创建通常由AnnotationAwareAspectJAutoProxyCreator在postProcessAfterInitialization中创建代理。
事件机制事件广播器的初始化、监听器的注册、事件的发布流程。

💡 七、最后的小建议

  • 不要试图一次性读懂所有细节:先抓住主线(Bean 的创建),再分支探索(如 AOP、事务、Web 启动)。

  • 结合 Spring 官方文档:文档中对 IoC 容器的解释可以帮助你理解设计意图。

  • 多画图:画出流程时序图或状态图,有助于形成整体认知。

按照这个拆解方法,相信你能够逐步攻破refresh()方法,从而掌握 Spring 容器的核心精髓。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询