obtainFreshBeanFactory() 方法细节详解
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 (可刷新式)
-
代表实现:
ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext等基于 XML 的经典容器。 -
特点:每次
refresh()都会销毁原有的 BeanFactory,重新创建一个全新的DefaultListableBeanFactory,并重新加载所有 Bean 定义。这使得容器支持配置动态刷新(虽然实际很少用)。
2. GenericApplicationContext (不可刷新式)
-
代表实现:
AnnotationConfigApplicationContext、AnnotationConfigWebApplicationContext等基于注解的容器。 -
特点:在构造函数中就已经创建了
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()是模板方法,由具体子类(如XmlBeanDefinitionReader、GroovyBeanDefinitionReader)完成 Bean 定义的解析和注册。
四、关键细节深入
4.1 BeanDefinition 的加载过程
以经典的 XmlWebApplicationContext 为例,它的 loadBeanDefinitions() 会:
-
创建一个
XmlBeanDefinitionReader。 -
将 BeanFactory 作为注册表传给 reader。
-
设置资源加载器、环境等。
-
调用
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 的生命周期。
更多推荐

所有评论(0)