Spring 源码解析:obtainFreshBeanFactory() 方法深度剖析与面试指南

138 阅读4分钟

Spring 源码解析:obtainFreshBeanFactory() 方法深度剖析与面试指南

引言

在 Spring 框架中,AbstractApplicationContext#refresh() 是容器初始化的核心入口方法,而 obtainFreshBeanFactory() 是其第二个关键步骤。该方法负责创建并配置 BeanFactory,加载并注册 Bean 定义(BeanDefinition),是 Spring IOC 容器初始化的基石。本文将通过源码逐行分析 obtainFreshBeanFactory(),并总结高频面试考点。


一、obtainFreshBeanFactory() 方法的作用

obtainFreshBeanFactory() 的核心任务是为 Spring 容器创建并初始化 BeanFactory,具体包含以下步骤:

  1. 销毁旧的 BeanFactory(如果存在),避免重复加载。
  2. 创建新的 BeanFactory(默认使用 DefaultListableBeanFactory)。
  3. 配置 BeanFactory,包括设置序列化 ID、是否允许 Bean 覆盖、是否支持循环依赖等。
  4. 加载 Bean 定义,解析 XML 或注解配置,生成 BeanDefinition 并注册到 BeanFactory 中。
  5. 返回初始化的 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 配置为例:

  1. 创建 XmlBeanDefinitionReader:用于读取 XML 文件。
  2. 加载资源:将配置文件转换为 Resource 对象。
  3. 解析 XML 为 Document:使用 DocumentLoader 加载并验证 XML。
  4. 解析 Document 节点:遍历 XML 标签,解析 <bean><component-scan> 等元素。
  5. 注册 BeanDefinition:将解析后的 BeanDefinition 存入 BeanFactorybeanDefinitionMap

关键代码片段

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 如何解决循环依赖?
  • 答案:通过三级缓存(singletonFactoriesearlySingletonObjectssingletonObjects)提前暴露未完全初始化的 Bean。allowCircularReferences 属性控制是否启用此机制。
4. loadBeanDefinitions() 如何解析 XML 配置文件?
  • 答案:使用 XmlBeanDefinitionReader 将 XML 转换为 Resource,解析为 Document,遍历节点生成 BeanDefinition,最终注册到 BeanFactory
5. 如何自定义 BeanFactory 的配置?
  • 答案:通过重写 customizeBeanFactory() 方法,可修改 allowBeanDefinitionOverridingallowCircularReferences 属性。

四、总结与扩展

  • 设计模式obtainFreshBeanFactory() 体现了模板方法模式,父类定义流程,子类实现具体步骤(如 loadBeanDefinitions())。
  • 性能优化:通过复用 BeanFactory 和缓存机制减少重复解析开销。
  • 扩展性:可通过实现 BeanDefinitionReader 扩展配置加载方式(如 JSON、YAML)。

附:典型面试题

Q: 如果 BeanFactory 已存在,refreshBeanFactory() 会如何处理?
A: 销毁所有单例 Bean 并关闭旧工厂,然后创建新工厂,确保容器状态干净。

Q: 如何禁用 Spring 的循环依赖支持?
A: 在 customizeBeanFactory() 中设置 setAllowCircularReferences(false)


通过深入分析 obtainFreshBeanFactory(),开发者不仅能掌握 Spring 容器的初始化机制,还能理解其设计哲学与扩展点。在面试中,结合源码和实际场景回答问题,将显著提升技术深度评价。