Spring 源码解析:obtainFreshBeanFactory() 方法深度剖析与面试指南
引言
在 Spring 框架中,AbstractApplicationContext#refresh() 是容器初始化的核心入口方法,而 obtainFreshBeanFactory() 是其第二个关键步骤。该方法负责创建并配置 BeanFactory,加载并注册 Bean 定义(BeanDefinition),是 Spring IOC 容器初始化的基石。本文将通过源码逐行分析 obtainFreshBeanFactory(),并总结高频面试考点。
一、obtainFreshBeanFactory() 方法的作用
obtainFreshBeanFactory() 的核心任务是为 Spring 容器创建并初始化 BeanFactory,具体包含以下步骤:
- 销毁旧的
BeanFactory(如果存在),避免重复加载。 - 创建新的
BeanFactory(默认使用DefaultListableBeanFactory)。 - 配置
BeanFactory,包括设置序列化 ID、是否允许 Bean 覆盖、是否支持循环依赖等。 - 加载 Bean 定义,解析 XML 或注解配置,生成
BeanDefinition并注册到BeanFactory中。 - 返回初始化的
BeanFactory,供后续步骤(如依赖注入、Bean 初始化)使用。
二、源码逐行解析
1. 方法入口与流程
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); // 核心逻辑:创建并配置 BeanFactory
return getBeanFactory(); // 返回初始化后的 BeanFactory
}
refreshBeanFactory():抽象方法,由AbstractRefreshableApplicationContext实现,负责销毁旧工厂、创建新工厂并加载 Bean 定义。getBeanFactory():返回已初始化的BeanFactory,若未初始化则抛出异常。
2. refreshBeanFactory() 核心逻辑
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { // 检查是否存在旧工厂
destroyBeans(); // 销毁所有单例 Bean
closeBeanFactory(); // 关闭旧工厂
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); // 创建新工厂
beanFactory.setSerializationId(getId()); // 设置序列化 ID
customizeBeanFactory(beanFactory); // 配置工厂属性
loadBeanDefinitions(beanFactory); // 加载 Bean 定义
this.beanFactory = beanFactory; // 赋值给当前上下文
} catch (IOException ex) { /* 异常处理 */ }
}
createBeanFactory():实例化DefaultListableBeanFactory,这是 Spring 最强大的BeanFactory实现,支持 Bean 定义注册、依赖注入、AOP 等核心功能。customizeBeanFactory():配置BeanFactory的两个关键属性:allowBeanDefinitionOverriding:是否允许同名 Bean 覆盖(默认允许)。allowCircularReferences:是否允许循环依赖(默认允许)。
3. loadBeanDefinitions() 详解
此方法负责解析配置文件(如 XML),生成 BeanDefinition 并注册到 BeanFactory。以 XML 配置为例:
- 创建
XmlBeanDefinitionReader:用于读取 XML 文件。 - 加载资源:将配置文件转换为
Resource对象。 - 解析 XML 为
Document:使用DocumentLoader加载并验证 XML。 - 解析
Document节点:遍历 XML 标签,解析<bean>、<component-scan>等元素。 - 注册
BeanDefinition:将解析后的BeanDefinition存入BeanFactory的beanDefinitionMap。
关键代码片段:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(configLocations); // 加载配置路径
}
最终通过 doLoadBeanDefinitions() 完成 XML 到 BeanDefinition 的转换和注册。
三、高频面试考点与答案
1. obtainFreshBeanFactory() 在 Spring 启动流程中的作用是什么?
- 答案:它是容器初始化的核心步骤,负责创建
BeanFactory、加载并注册 Bean 定义,为后续依赖注入和 Bean 实例化提供基础。
2. DefaultListableBeanFactory 的特点是什么?
- 答案:它是 Spring 默认的
BeanFactory实现,支持 Bean 定义注册、依赖注入、注解处理等,是功能最全的BeanFactory。
3. Spring 如何解决循环依赖?
- 答案:通过三级缓存(
singletonFactories、earlySingletonObjects、singletonObjects)提前暴露未完全初始化的 Bean。allowCircularReferences属性控制是否启用此机制。
4. loadBeanDefinitions() 如何解析 XML 配置文件?
- 答案:使用
XmlBeanDefinitionReader将 XML 转换为Resource,解析为Document,遍历节点生成BeanDefinition,最终注册到BeanFactory。
5. 如何自定义 BeanFactory 的配置?
- 答案:通过重写
customizeBeanFactory()方法,可修改allowBeanDefinitionOverriding和allowCircularReferences属性。
四、总结与扩展
- 设计模式:
obtainFreshBeanFactory()体现了模板方法模式,父类定义流程,子类实现具体步骤(如loadBeanDefinitions())。 - 性能优化:通过复用
BeanFactory和缓存机制减少重复解析开销。 - 扩展性:可通过实现
BeanDefinitionReader扩展配置加载方式(如 JSON、YAML)。
附:典型面试题
Q: 如果 BeanFactory 已存在,refreshBeanFactory() 会如何处理?
A: 销毁所有单例 Bean 并关闭旧工厂,然后创建新工厂,确保容器状态干净。
Q: 如何禁用 Spring 的循环依赖支持?
A: 在 customizeBeanFactory() 中设置 setAllowCircularReferences(false)。
通过深入分析 obtainFreshBeanFactory(),开发者不仅能掌握 Spring 容器的初始化机制,还能理解其设计哲学与扩展点。在面试中,结合源码和实际场景回答问题,将显著提升技术深度评价。