obtainFreshBeanFactory() 是 Spring refresh() 方法中的第二个核心步骤,它的职责是获取或重新创建 BeanFactory,并加载所有 Bean 定义

一、方法定义与位置

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

  • 方法签名protected ConfigurableListableBeanFactory obtainFreshBeanFactory()

  • 调用时机:在 prepareRefresh() 之后立即执行

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 刷新 BeanFactory:如果是可刷新的上下文,则销毁原有 BeanFactory,创建新的并加载 Bean 定义
    refreshBeanFactory();
    // 获取刚刚刷新好的 BeanFactory
    return getBeanFactory();
}

这个方法虽短,但承担了销毁旧工厂 → 创建新工厂 → 加载 Bean 定义的完整过程,而具体实现则交给子类完成。

二、核心设计:两种典型的子类实现

Spring 的 ApplicationContext 主要有两条继承路线,分别对应不同的 BeanFactory 管理策略:

1. AbstractRefreshableApplicationContext (可刷新式)

  • 代表实现ClassPathXmlApplicationContextFileSystemXmlApplicationContextXmlWebApplicationContext 等基于 XML 的经典容器。

  • 特点:每次 refresh() 都会销毁原有的 BeanFactory,重新创建一个全新的 DefaultListableBeanFactory,并重新加载所有 Bean 定义。这使得容器支持配置动态刷新(虽然实际很少用)。

2. GenericApplicationContext (不可刷新式)

  • 代表实现AnnotationConfigApplicationContextAnnotationConfigWebApplicationContext 等基于注解的容器。

  • 特点:在构造函数中就已经创建了 DefaultListableBeanFactory,且整个生命周期内只会有一个 BeanFactory,不允许刷新。如果调用 refresh() 多次,会抛出异常。

你正在使用的 AnnotationConfigApplicationContext 就属于第二种,它的 BeanFactory 是“一次性”创建好的。

三、源码逐层深入

3.1 refreshBeanFactory() 抽象方法

在 AbstractApplicationContext 中,refreshBeanFactory() 被声明为抽象方法:

protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

不同的子类提供了完全不同的实现。

3.2 GenericApplicationContext 的实现(你的场景)

public class GenericApplicationContext extends AbstractApplicationContext
        implements BeanDefinitionRegistry {

    private final DefaultListableBeanFactory beanFactory;
    private boolean refreshed = false;

    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }

    @Override
    protected final void refreshBeanFactory() throws IllegalStateException {
        if (this.refreshed) {
            throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        }
        this.beanFactory.setSerializationId(getId());
        this.refreshed = true;
    }

    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        return this.beanFactory;
    }
}
  • beanFactory 在构造函数中就已经创建好。

  • refreshBeanFactory() 只是设置序列化 ID 并标记已刷新,不会重建工厂。

  • getBeanFactory() 直接返回同一个 beanFactory

3.3 AbstractRefreshableApplicationContext 的实现(用于对比理解)

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {

    private DefaultListableBeanFactory beanFactory;

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        // 如果已有 BeanFactory,先销毁
        if (hasBeanFactory()) {
            destroyBeans();          // 销毁所有单例 Bean
            closeBeanFactory();      // 清空引用
        }
        try {
            // 1. 创建新的 BeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());

            // 2. 定制 BeanFactory(是否允许覆盖、是否允许循环引用等)
            customizeBeanFactory(beanFactory);

            // 3. **加载 Bean 定义(关键)**
            loadBeanDefinitions(beanFactory);

            // 4. 持有新的 BeanFactory
            this.beanFactory = beanFactory;
        } catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source", ex);
        }
    }

    // 创建默认的 BeanFactory
    protected DefaultListableBeanFactory createBeanFactory() {
        return new DefaultListableBeanFactory(getInternalParentBeanFactory());
    }

    // 留给子类定制的钩子
    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        // 设置是否允许 Bean 定义覆盖
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        // 设置是否允许循环引用
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

    // 抽象方法:加载 Bean 定义,由子类(如 XmlWebApplicationContext)实现
    protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
            throws BeansException, IOException;
}
  • destroyBeans() 会调用所有单例 Bean 的 destroy() 方法,清空工厂缓存。

  • createBeanFactory() 创建 DefaultListableBeanFactory,它是 Spring 中最强大的 BeanFactory 实现。

  • customizeBeanFactory() 允许子类配置是否允许 Bean 定义覆盖(默认允许)、是否允许循环引用(默认允许)。

  • loadBeanDefinitions() 是模板方法,由具体子类(如 XmlBeanDefinitionReaderGroovyBeanDefinitionReader)完成 Bean 定义的解析和注册。

四、关键细节深入

4.1 BeanDefinition 的加载过程

以经典的 XmlWebApplicationContext 为例,它的 loadBeanDefinitions() 会:

  1. 创建一个 XmlBeanDefinitionReader

  2. 将 BeanFactory 作为注册表传给 reader。

  3. 设置资源加载器、环境等。

  4. 调用 reader.loadBeanDefinitions(configLocations) 读取 XML 文件,解析出一个个 <bean> 标签,转化为 BeanDefinition,并注册到 BeanFactory 的 beanDefinitionMap 中。

对于注解驱动(AnnotationConfigApplicationContext),虽然它属于 GenericApplicationContext 路线,但 Bean 定义的加载其实是在构造 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 时完成的,而不是在 refreshBeanFactory() 里。这是因为 GenericApplicationContext 的 refreshBeanFactory() 不做加载,它把加载前置到了构造阶段。但本质上,最终都是将 BeanDefinition 注册到 DefaultListableBeanFactory 的 beanDefinitionMap 中。

4.2 BeanFactory 的定制

在 AbstractRefreshableApplicationContext 中,customizeBeanFactory() 允许我们设置两个重要标志:

  • allowBeanDefinitionOverriding:默认 true,允许后注册的 Bean 定义覆盖之前同名的定义。如果设置为 false,重复定义会抛出异常。

  • allowCircularReferences:默认 true,允许循环依赖(通过三级缓存解决)。如果设置为 false,遇到循环依赖会直接抛出 BeanCurrentlyInCreationException

这些设置会直接影响容器的行为,你可以根据实际需求在自定义的 ApplicationContext 中调整。

4.3 返回的 BeanFactory

getBeanFactory() 返回的是 ConfigurableListableBeanFactory,它提供了获取 Bean、类型转换、依赖检查等核心功能。后续的 prepareBeanFactory()postProcessBeanFactory() 等方法都是基于这个工厂对象进行操作。


五、与后续流程的关系

执行完 obtainFreshBeanFactory() 后,Spring 有了一个全新的、包含所有 Bean 定义的 BeanFactory(或者对于 GenericApplicationContext 来说,是同一个已经填充了 Bean 定义的工厂)。紧接着的步骤是:

  • prepareBeanFactory(beanFactory):对工厂进行标准化设置(如添加 ApplicationContextAwareProcessor、注册 environment 等单例)。

  • postProcessBeanFactory(beanFactory):子类可以进一步修饰工厂(如 Web 环境注册 ServletContext 相关后置处理器)。

  • invokeBeanFactoryPostProcessors(beanFactory):执行 BeanFactoryPostProcessor,对 Bean 定义进行修改。

  • ……

可以说,obtainFreshBeanFactory() 为整个 IoC 容器的运转提供了最基础的原料——Bean 定义。


六、调试建议

6.1 如何观察 BeanDefinition 的加载?

如果你使用的是 AnnotationConfigApplicationContext,可以在以下位置设置断点:

  • AnnotatedBeanDefinitionReader.doRegisterBean():注册通过 @Configuration 类或 @Bean 方法定义的 Bean。

  • ClassPathBeanDefinitionScanner.scan():扫描指定包下的组件并注册。

  • DefaultListableBeanFactory.registerBeanDefinition():最终将 BeanDefinition 放入 beanDefinitionMap 的地方。

如果你使用的是 XML 容器(ClassPathXmlApplicationContext),可以关注:

  • XmlBeanDefinitionReader.loadBeanDefinitions() → doLoadBeanDefinitions() → registerBeanDefinitions()

6.2 观察 BeanFactory 的创建

  • 在 GenericApplicationContext 构造函数中断点,观察 DefaultListableBeanFactory 的诞生。

  • 在 AbstractRefreshableApplicationContext.refreshBeanFactory() 中断点,观察 createBeanFactory()customizeBeanFactory()loadBeanDefinitions() 的调用顺序。

6.3 验证 BeanDefinition 覆盖

尝试在同一个上下文中定义两个同名的 Bean(例如通过 XML 和注解),观察 allowBeanDefinitionOverriding 对结果的影响。


七、常见问题

❓ GenericApplicationContext 如何加载 BeanDefinition?

它并不在 refreshBeanFactory() 中加载,而是通过以下方式提前注册:

  • 构造函数中会创建 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner,它们可以注册单个类或扫描包。

  • 你可以在调用 refresh() 之前手动调用 register(Class<?>... annotatedClasses) 或 scan(String... basePackages) 来注册 Bean 定义。

  • 一旦调用了 refresh(),就不能再注册新的 Bean 定义了。

❓ AbstractRefreshableApplicationContext 真的支持动态刷新吗?

理论上,你可以关闭容器(close())再重新调用 refresh(),它会销毁旧工厂、创建新工厂并重新加载定义。但这样做会丢失所有 Bean 的状态,不是通常意义上的“热加载”。Spring Boot 的 DevTools 提供了类加载级的重载,但原理与此不同。

❓ 为什么需要 setSerializationId(getId())

为 BeanFactory 设置序列化 ID 是为了在反序列化时能够关联回正确的 ApplicationContext。如果 BeanFactory 被序列化(例如在 Session 中存储),反序列化时能通过 ID 找到所属的容器。


八、总结

  • obtainFreshBeanFactory() 是获取(或创建)BeanFactory 并加载所有 Bean 定义的关键步骤。

  • 它通过 refreshBeanFactory() 抽象方法,将具体实现下放给子类,体现了模板方法模式。

  • GenericApplicationContext(你的场景)采用单工厂模型,Bean 定义在 refresh() 之前已注册。

  • AbstractRefreshableApplicationContext 支持动态刷新,每次 refresh() 都会重新创建工厂并加载定义。

  • 这个方法为后续的 Bean 后置处理、实例化等流程提供了完整的 Bean 元数据(BeanDefinition)。

理解 obtainFreshBeanFactory() 有助于你把握 Spring 容器启动的“资源准备”阶段,从而更深入地追踪 Bean 的生命周期。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐