人人都会AI编程

26.2 IoC 容器源码核心流程

更新时间:2026-07-11

理解 IoC 容器的源码,不是为了背诵实现细节,而是为了在遇到诡异的 Bean 加载失败、循环依赖报错、@PostConstruct 未执行等问题时,能有一套清晰的分析框架。Spring IoC 容器的主线流程可以归纳为 容器启动 → BeanDefinition 加载与注册 → Bean 实例化与依赖注入 → 初始化 四个阶段。下面以 AnnotationConfigApplicationContext 为入口,展示最常用场景下的核心链路。

26.2.1 容器启动与配置类注册

AnnotationConfigApplicationContext 的构造器主要完成三件事:创建内部的 DefaultListableBeanFactory、注册配置类本身的 BeanDefinition、以及调用 refresh() 启动容器。

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();                               // 1. 实例化 DefaultListableBeanFactory
    register(componentClasses);           // 2. 将配置类注册为 BeanDefinition
    refresh();                            // 3. 容器刷新入口
}

refresh() 是 Spring 容器最核心的方法,所有 ApplicationContext 实现都会执行相同的刷新步骤,它定义了容器启动的完整生命周期:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();                   // 准备环境、校验属性
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);   // 添加系统 BeanPostProcessor 等
        postProcessBeanFactory(beanFactory);// 空方法,留给子类扩展
        invokeBeanFactoryPostProcessors(beanFactory); // 处理 BeanFactoryPostProcessor
        registerBeanPostProcessors(beanFactory);     // 注册 BeanPostProcessor
        initMessageSource();               // 国际化
        initApplicationEventMulticaster(); // 事件广播器
        onRefresh();                       // 子类扩展(如启动 WebServer)
        registerListeners();               // 注册事件监听器
        finishBeanFactoryInitialization(beanFactory); // 初始化所有剩余的单例 Bean
        finishRefresh();                   // 清理缓存、发布 ContextRefreshedEvent
    }
}

篇幅所限,这里不逐一展开每个步骤,重点关注 BeanDefinition 的加载和 Bean 的实例化过程。

26.2.2 BeanDefinition 的加载与注册

invokeBeanFactoryPostProcessors 步骤会调用所有注册的 BeanFactoryPostProcessor,其中最关键的当属 ConfigurationClassPostProcessor。它负责处理 @Configuration 类,通过 ConfigurationClassParser 解析 @ComponentScan@Import@Bean 等方法,最终将扫描到的组件转化为 BeanDefinition 并注册到 DefaultListableBeanFactorybeanDefinitionMap 中。

核心链路简化为:

  1. ConfigurationClassPostProcessor.processConfigBeanDefinitions()
  2. 遍历所有配置类,调用 ConfigurationClassParser.parse()
  3. 解析 @ComponentScan,扫描指定包路径,将 @Component 等注解标注的类包装为 ScannedGenericBeanDefinition
  4. 解析 @Import@Bean 方法注册额外的 BeanDefinition
  5. 调用 DefaultListableBeanFactory.registerBeanDefinition() 将 BeanDefinition 存入 beanDefinitionMap(ConcurrentHashMap),同时更新 beanDefinitionNames 列表。

此时,容器包含了所有要管理的 Bean 的定义信息,但还没有创建任何实例(除了部分 BeanFactoryPostProcessorBeanPostProcessor)。

26.2.3 单例 Bean 的初始化主线

finishBeanFactoryInitialization(beanFactory) 负责实例化所有非懒加载的单例 Bean。内部调用 beanFactory.preInstantiateSingletons(),遍历 beanDefinitionNames,对每个非抽象的 Bean 调用 getBean(beanName)

getBean 是 Bean 获取的统一入口,它委托给 doGetBean(),并经历以下关键步骤:

1. 尝试从缓存获取
首先检查 getSingleton(beanName),如果对象已经在单例池(singletonObjects,一级缓存)中存在,直接返回。这保证了单例的复用性。

2. 处理循环依赖的早期暴露
若缓存中不存在,开始创建新的单例。调用 getSingleton(String beanName, ObjectFactory<?> singletonFactory),该方法会将当前 Bean 名放入“正在创建”标记(singletonsCurrentlyInCreation)中,然后回调 singletonFactorycreateBean 方法。

3. 实例化 Bean(createBeanInstance)
AbstractAutowireCapableBeanFactory.createBeanInstance() 负责创建原始对象。它会:

  • 通过 resolveBeanClass 加载 Bean 类
  • 判断是否有 Supplier@Lookup 方法或工厂方法,若无,则选择合适的构造器进行实例化(autowireConstructorinstantiateBean)。实例化通常使用反射或 CGLIB 动态子类化,最终产生一个 Bean 实例,但此时属性尚未填充。

4. 允许后处理器提前处理
实例化后,调用 applyMergedBeanDefinitionPostProcessors,将合并后的 BeanDefinition 交给 MergedBeanDefinitionPostProcessor 处理,例如 AutowiredAnnotationBeanPostProcessor 收集 @Autowired 注入点。

5. 提前暴露半成品解决循环依赖
如果当前 Bean 是单例、允许循环引用且正在创建中,Spring 会调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))。这里会将一个能产生早期引用的 ObjectFactory 放入三级缓存(singletonFactories)。当 B 在创建过程中需要注入 A 时,可以从三级缓存获取 A 的早期引用(如果有代理,此处会提前生成代理对象),从而打破循环。

6. 属性填充(populateBean)
populateBean(beanName, mbd, instanceWrapper) 完成依赖注入。它会遍历所有 InstantiationAwareBeanPostProcessor,调用 postProcessProperties 来处理 @Autowired@Value@Resource 等注解的注入。例如 AutowiredAnnotationBeanPostProcessor 通过反射找到标记的字段或方法,从容器中解析并注入依赖。

7. 初始化(initializeBean)
属性注入完成后,执行初始化回调:

  • 调用 invokeAwareMethods:如果 Bean 实现了 BeanNameAwareBeanClassLoaderAwareBeanFactoryAware,注入相应资源。
  • 调用所有 BeanPostProcessor.postProcessBeforeInitialization:其中 ApplicationContextAwareProcessor 会在此处注入 ApplicationContext 等 Aware。
  • 调用 invokeInitMethods:先检查是否实现 InitializingBean,调用 afterPropertiesSet;再调用用户自定义的 init-method@PostConstruct 标注的方法(注意:@PostConstruct 实际由 CommonAnnotationBeanPostProcessorpostProcessBeforeInitialization 中优先执行)。
  • 调用所有 BeanPostProcessor.postProcessAfterInitialization:这里可能生成 AOP 代理对象,例如 AbstractAutoProxyCreator 会判断是否需要创建代理,如果需要则返回代理对象,替换原始 Bean。

8. 放入单例池
经过初始化后的最终 Bean(可能是代理)被放入一级缓存 singletonObjects,并从二级、三级缓存中移除,完成创建。

26.2.4 三级缓存解决循环依赖的核心机制

这是面试和实际问题的高频点,有必要单独说明。Spring 使用三级缓存:

  • singletonObjects(一级):完全初始化好的单例池。
  • earlySingletonObjects(二级):存放早期暴露的未完全初始化的 Bean(已从三级移入)。
  • singletonFactories(三级):存放可生成 Bean 早期引用的 ObjectFactory。

当 A 与 B 循环依赖时,流程如下:

  1. 创建 A,实例化后将 ObjectFactory 放入三级缓存,然后填充属性时发现需要 B。
  2. 尝试获取 B,B 不存在,开始创建 B。
  3. B 实例化后,填充属性时需要 A,去缓存查找 A。
  4. 在三级缓存找到 A 的 ObjectFactory,调用 getObject()(可能触发 getEarlyBeanReference 产生 A 的代理),将结果放入二级缓存,并从三级缓存移除。
  5. B 获得 A 的早期引用,完成属性填充和初始化,成为完整的单例放入一级缓存。
  6. 回到 A 的创建,A 继续完成属性填充(此时 B 已完整),初始化,最终放入一级。

三级缓存的关键在于 提前暴露一个对象引用,即便该对象尚未完全初始化。这只能解决单例的 Setter 注入循环依赖,无法解决构造器注入的循环依赖(因为构造器触发时就要求立刻获得依赖,根本来不及暴露)。

26.2.5 容器优雅关闭

当应用关闭时(如 context.close()),容器调用 doClose(),最终会回调每个单例 Bean 的销毁方法:先执行 DisposableBean.destroy(),再调用自定义的 destroy-method@PreDestroy 方法。CommonAnnotationBeanPostProcessor 负责 @PreDestroy 的调度。整个过程确保外部资源(连接池、线程池)被安全释放。


理解了这一主干流程,再遇到 NoSuchBeanDefinitionException、循环依赖错误、@PostConstruct 失效等问题时,你就能够快速定位是 BeanDefinition 未注册、构造器参数解析失败,还是后处理器未正确配置,从而对症下药。下一节我们将深入 ApplicationContextBeanFactory 的区别,进一步夯实容器基础。