 方法细节详解)
obtainFreshBeanFactory()是 Springrefresh()方法中的第二个核心步骤它的职责是获取或重新创建 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.1refreshBeanFactory()抽象方法在AbstractApplicationContext中refreshBeanFactory()被声明为抽象方法protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;不同的子类提供了完全不同的实现。3.2GenericApplicationContext的实现你的场景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.3AbstractRefreshableApplicationContext的实现用于对比理解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 返回的 BeanFactorygetBeanFactory()返回的是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 的生命周期。