京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?

本文 的 原文 地址

原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址

尼恩说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格,遇到很多很重要的相关面试题:

京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?

IoC 是什么?

IoC 容器初始化过程?

spring ioc容器 中,用到哪些设计模式?

最近有小伙伴在面 京东,问到了相关的面试题,可以说是逢面必问。

小伙伴没有系统的去梳理和总结,所以支支吾吾的说了几句,面试官不满意,面试挂了。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

最终,机会爆表,实现”offer自由” 。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V175版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取

本文作者:

  • 第一作者 老架构师 肖恩(肖恩 是尼恩团队 高级架构师,负责写此文的第一稿,初稿 )
  • 第二作者 老架构师 尼恩 (45岁老架构师, 负责 提升此文的 技术高度,让大家有一种 俯视 技术、俯瞰技术、 技术自由 的感觉

现状:能 暴击面官的 顶级高手,不到10%

Spring 的源码 非常重要,但是 很多人 , 在死记硬背。

90%的人, 在死记硬背。

回答不到 Spring 的源码 底层思维/ 底层原理

真正 做到 能 暴击面官的 ,比例 不到10%。

本文,尼恩从设计模式入手 , 带大家 穿透 Spring 的源码 , 帮大家 暴击面官。

Spring IOC容器概述

Spring IoC容器,主要负责bean的定义加载,实例化、配置、装配。

简而言之,Spring IoC容器是管理这些bean的(这里所说的bean指的是组成你的应用程序中的对象,并且这些对象被Spring所管理)。

容器如何知道哪些对象要进行实例化、配置和装配的呢?是通过读取配置文件元数据来达到这个效果的,配置文件元数据是用xml配置、Java注解和Java代码配置来表示的。

这使得作为程序员的我们,只需要向Spring容器提供配置元数据,Spring容器就能在我们的应用中实例化、配置和装配这些对象。

下面这张图从更高的视角展示了Spring是怎样工作的。

你的应用程序中的类是和配置元数据组合在一起,以便在ApplicationContext创建和初始化之后,你拥有了一个完全配置的、可执行的系统。

容器魔法

Spring IoC 容器的设计主要是基于以下两个接口:

  • 实现BeanFactory接口的简单容器
  • 实现ApplicationContext接口的高级容器

下面分别分析下这两个接口

ioc容器是什么?

Spring 的IOC容器主要体现在2个接口‌BeanFactory‌,和ApplicationContext‌

BeanFactory‌:

可以理解成简单容器,Spring 最基础的 IoC 容器接口,采用 ‌延迟加载 (Lazy Loading)‌,提供最核心的 Bean 管理功能(创建、依赖注入、生命周期管理)。它仅关注 Bean 的实例化和配置,不支持企业级特性。

‌ApplicationContext‌:

可以理解成高级容器,是BeanFactory的子接口,预加载 (Eager Loading)‌,在继承其所有功能的基础上,提供了全面的企业级功能扩展,包括:

  • 国际化 (MessageSource)
  • 事件发布/监听机制 (ApplicationEventPublisher)
  • 便捷的资源访问 (ResourceLoader,支持 classpath:, file: 等前缀)
  • 内置的 AOP 支持(自动代理)
  • 注解支持 (@Autowired, @ComponentScan 等自动生效)
  • 环境抽象 (Environment,支持 profiles 和 properties)
  • 自动注册 BeanPostProcessorBeanFactoryPostProcessor

BeanFactory

可以把 BeanFactory 想象成一个简单的“工具箱”,它是 Spring 最基础的容器。

这个工具箱的主要功能是帮你管理 Bean(也就是那些你需要用到的对象)。

它会按需创建这些对象,只有在你真正需要的时候才会去生成它们(这叫“延迟加载”)。

简单来说,BeanFactory 只负责最核心的事情:

  • 创建对象
  • 给对象注入依赖
  • 管理对象的生命周期

但它功能比较简单,就像一个普通的手工工具箱,只关注怎么把对象弄出来,不提供太多高级功能。

ApplicationContext

ApplicationContext 就像是一个“高级工具箱”,它是 BeanFactory 的升级版。

除了继承了 BeanFactory 的所有功能外,还增加了很多实用的企业级特性。

它的特点是“提前准备好所有东西”(这叫“预加载”),所以一启动就能直接用。

ApplicationContext 提供的功能包括:

(1) 国际化支持:比如可以根据用户的语言自动切换提示信息。

(2) 事件机制:可以发布和监听事件,有点像微信群里发消息,大家都能收到。

(3) 资源访问:方便读取文件或者配置,支持一些特殊的路径写法(比如 classpath:file:)。

(4) AOP 支持:自动帮你处理一些重复性的工作,比如日志记录或权限检查。

(5) 注解支持:像 @Autowired 这种注解可以直接生效,不用手动配置。

(6) 环境管理:可以轻松切换不同的配置(比如开发环境、测试环境、生产环境)。

(7) 自动注册扩展点:比如 BeanPostProcessorBeanFactoryPostProcessor,可以让开发者自定义一些额外的操作。

基础知识: Bean 定义Bean 实例

老架构师尼恩提示,后面会反复提到 Bean 定义Bean 实例 ,这里进行 复习一下, 帮助大家进行后面的理解。

在 Spring 框架中, Bean 定义Bean 实例 是一个重要的设计概念。

并且, Bean 定义Bean 实例 之间存在着重要的关系,大致如下图:

1. Bean 定义 (BeanDefinition)

本质:描述 Bean 的元数据(“配方”)

包含内容:

  • 类路径(beanClass)
  • 作用域(singleton/prototype)
  • 初始化方法
  • 属性值(propertyValues)

存储位置: BeanDefinition 存储在 DefaultListableBeanFactory 中的 beanDefinitionMap

2. Bean 实例

本质:根据定义创建的实际对象(“成品”)

生命周期:

  • BeanFactory 基于 BeanDefinition 创建
  • 通过依赖注入装配属性
  • 执行初始化回调方法(如 @PostConstruct

存储位置

单例 Bean实例 存储在DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry中维护的singletonObjects(也是一个ConcurrentHashMap)中, 也就是 三级缓存中的一级缓存。 当然,‌原型 Bean每次请求时创建新实例,不缓存。

关键关系特性

特性Bean 定义(BeanDefinition)Bean 实例
存在形式配置元数据(XML/注解/JavaConfig)Java 对象
创建时机容器启动阶段根据作用域延迟/立即创建
数量关系1个定义可能对应多个实例(如 prototype)
获取方式BeanFactory.getBeanDefinition()BeanFactory.getBean()
存储位置BeanDefinitionRegistry单例池(SingletonObjects Map)

言归正传。

BeanFactory :Spring 核心IoC容器接口

BeanFactory是Spring框架的核心IoC容器接口,负责管理Bean的生命周期,包括实例化、配置和依赖注入。

BeanFactory 核心实现类DefaultListableBeanFactory通过BeanDefinition存储配置元数据,支持延迟加载和三级缓存解决循环依赖。

相比ApplicationContext更轻量,BeanFactory 适合资源敏感场景,可扩展机制包括BeanPostProcessorFactoryBean的扩展

继承关系图 如下:

image-20250617181947588

继承关系图中核心组件:

  • ListableBeanFactory:支持批量查询 Bean 信息(如 getBeanDefinitionNames()
  • HierarchicalBeanFactory:支持父子容器层级
  • ConfigurableBeanFactory:提供动态配置能力(如作用域、后置处理器注册)
  • BeanDefinitionRegistry:Bean 定义注册
  • DefaultSingletonBeanRegistry:单例缓存管理,解决循环依赖的三级缓存定义在这里
  • AutowireCapableBeanFactory 是 Spring 框架的核心接口,扩展了 BeanFactory,提供自动装配(Autowire)能力。
  • DefaultListableBeanFactory:是Spring框架中‌最核心的IoC容器实现‌,集成了Bean定义管理、依赖注入、循环依赖解决(三级缓存)及生命周期控制等核心功能,是Spring Bean管理的底层基石

BeanFactory默认实现DefaultListableBeanFactory支持延迟加载,整合了Bean定义注册、依赖查找等基础能力,时序图如下
image-20250617181947588

示例代码


// 1. 创建核心容器
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

// 2. 注册 Bean 定义(XML 解析器)
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("beans.xml"));

// 3. 手动添加后置处理器
beanFactory.addBeanPostProcessor(new CustomBeanPostProcessor());

// 4. 获取 Bean(触发延迟初始化)
UserService userService = beanFactory.getBean("userService", UserService.class);

注意‌:XmlBeanFactory 已过时(Spring 5+),推荐组合使用 DefaultListableBeanFactory + BeanDefinitionReader

ApplicationContext :Spring ‌企业级应用的核心容器‌

ApplicationContext 是 Spring ‌企业级应用的核心容器‌,可以理解成高级容器,

ApplicationContextBeanFactory 基础上扩展了国际化、资源加载、事件机制等高级功能,通过 refresh() 方法实现完整的容器生命周期管理

ApplicationContext 继承关系图 如下:

image-20250617184653099

ApplicationContext 字段级的 继承关系图 如下:

image-20250617180104276

ApplicationContext继承的接口分为5类

(1)BeanFactory:提供了能够管理任何对象的高级配置机制,这个接口是Spring框架中比较重要的一个接口。

  • ListableBeanFactory:从该接口的名字就能知道,该接口除了拥有BeanFactory的功能外,该接口还有能列出factory中所有bean的实例的能力。
  • HierarchicalBeanFactory:该接口除了拥有BeanFactory的功能外,还提供了BeanFactory分层的机制,查找bean的时候,除了在自身BeanFactory查找外,如果没有查找到,还会在父级BeanFactory进行查找。

(2)MessageSource:消息资源的处理,用于国际化。

(3)ApplicationEventPublisher:用于处理事件发布机制。

(4)EnvironmentCapable:提供了Environment的访问能力。

(5)ResourceLoader::用于加载资源的策略接口(例如类路径下的资源、系统文件下的资源等等)。

  • ResourcePatternResolver:用于将位置模式(例如Ant风格的路径模式)解析成资源对象的策略接口。classpath*:前缀能匹配所以类路径下的资源。

ApplicationContext中的关键方法

  • getBean():获取 Bean 实例(继承自 BeanFactory
  • getMessage():获取国际化消息(如 context.getMessage("hi", null, Locale.CHINA)
  • getResource():加载资源文件(如 classpath:application.yml
  • publishEvent():发布自定义事件

ApplicationContext 常用实现类

实现类适用场景特点
ClassPathXmlApplicationContext基于类路径的 XML 配置加载 classpath*:config.xml 文件
FileSystemXmlApplicationContext基于文件系统的 XML 配置加载磁盘路径的配置文件(如 file:/config.xml
AnnotationConfigApplicationContext基于注解的配置支持 @ComponentScan@Bean 等注解
AnnotationConfigWebApplicationContextWeb 应用注解配置集成 Servlet 环境,支持 @Controller

示例代码:


基于注解的容器初始化
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取国际化消息
String msg = context.getMessage("welcome", null, Locale.ENGLISH);  // 输出 "Hello" 
// 加载资源文件
Resource resource = context.getResource("classpath:config.yml");  // class path 资源 
// 发布自定义事件
context.publishEvent(new MyEvent("Custom Event"));  // 触发监听器逻辑 

BeanFactory和ApplicationContext的区别

image-20250617184954664

BeanFactory和ApplicationContext的 相同点

在功能上, ApplicationContext 是 BeanFactory 的超集,提供了全面的企业级支持和便利的开发体验,是绝大多数场景下的首选。

BeanFactory 则保留了作为轻量级基础容器的价值,适用于特定资源受限环境。

两者在核心的 Bean 管理能力上是相同的。

BeanFactory和ApplicationContext的 不同点

BeanFactory和ApplicationContext的 不同,主要体现在下面三个方面:

(1)设计定位和功能

BeanFactory‌: Spring 最基础的 IoC 容器接口,提供最核心的 Bean 管理功能(创建、依赖注入、生命周期管理)。它仅关注 Bean 的实例化和配置,不支持企业级特性。

‌ApplicationContext‌: 是BeanFactory的子接口,在继承其所有功能的基础上,提供了全面的企业级功能扩展,包括:

  • 国际化 (MessageSource)

  • 事件发布/监听机制 (ApplicationEventPublisher)

  • 便捷的资源访问 (ResourceLoader,支持 classpath:, file: 等前缀)

  • 内置的 AOP 支持(自动代理)

  • 注解支持 (@Autowired, @ComponentScan 等自动生效)

  • 环境抽象 (Environment,支持 profiles 和 properties)

  • 自动注册 BeanPostProcessorBeanFactoryPostProcessor

(2)Bean 加载机制

BeanFactory‌: 采用 ‌延迟加载 (Lazy Loading)‌, 懒汉子模式

默认情况下,只有在首次调用 getBean() 请求某个 Bean 时,才会实例化并初始化该 Bean。容器启动速度快,但配置问题可能延后暴露。

ApplicationContext‌: 采用 ‌预加载 (Eager Loading)‌, 饿汉子模式

默认情况下,在容器启动过程中就会实例化并初始化所有的单例 (singleton) Bean。启动耗时稍长(尤其 Bean 多时),但能尽早发现配置错误(如依赖缺失),运行时获取 Bean 更快。

(3)使用场景

BeanFactory‌: 适用于‌资源高度受限的环境‌(如嵌入式系统、Applet)或对‌极致轻量级和快速启动‌有严格要求的场景。功能简单,内存占用更小。

ApplicationContext‌: 是‌绝大多数企业级应用开发的标准选择‌。它提供了开箱即用的丰富功能,简化了开发,是 Spring Boot 等现代框架默认使用的容器。虽然启动稍慢且内存占用略高,但其功能性和开发便捷性优势显著。

示例代码说明:


// BeanFactory 示例 (XmlBeanFactory 已过时, 此处仅作概念演示)
Resource resource = new ClassPathResource("beans.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource); // 此时并未创建 Bean
MyBean bean = beanFactory.getBean(MyBean.class); // 首次调用 getBean 时实例化

// ApplicationContext 示例
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); // 启动时即创建单例 Bean
MyBean bean = context.getBean(MyBean.class); // 直接获取已初始化的 Bean
// 还可使用额外功能,如事件发布
context.publishEvent(new MyCustomEvent(context));

最后总结下:

功能特性BeanFactoryApplicationContext
‌**Bean 管理 (创建, DI)**‌
‌**延迟加载 (默认)**‌✗ (预加载单例)
‌**AOP 集成 (自动代理)**‌
事件机制
‌**国际化 (i18n)**‌
‌**资源加载 (Resource)**‌✗ (需手动)✓ (内置)
‌**注解支持 (如 @Autowired)**‌✗ (需手动配置)
‌**自动组件扫描 (@ComponentScan)**‌
‌**环境抽象 (Profiles, Properties)**‌
自动注册 BeanPostProcessor✗ (需手动)

AbstractApplicationContext# refresh() 方法中有容器启动的12大关键步骤

AbstractApplicationContext#refresh() 方法中有容器启动的12大关键步骤,非常重要,总结下:

(1) prepareRefresh() - 准备刷新: 初始化启动标志、属性源校验、早期事件集合

(2) obtainFreshBeanFactory() - 获取新BeanFactory 创建/刷新BeanFactory,加载Bean定义,XML/注解配置解析、Bean定义注册发生在这里

(3) prepareBeanFactory() - 配置标准BeanFactory:设置类加载器、注册标准PostProcessor(比如:ApplicationContextAwareProcessor)

(4) postProcessBeanFactory() - 后处理BeanFactory:子类扩展点,修改Bean定义,比如Web容器注册Servlet相关处理器

(5) invokeBeanFactoryPostProcessors() - 执行工厂后处理器​​:@Configuration解析、@Value(${url.jdbc})占位符注入

(6) registerBeanPostProcessors() - 注册Bean后处理器​:AOP代理创建、@Autowired注入

(7) initMessageSource() - 初始化国际化

(8) initApplicationEventMulticaster() - 初始化事件广播器

(9) onRefresh() - 子类扩展刷新:模板方法供子类扩展,Spring Boot启动内嵌服务器在这

(10) registerListeners() - 注册监听器

(11) finishBeanFactoryInitialization() - 完成单例初始化:单例bean从这里开始创建

(12) finishRefresh() - 完成刷新

ApplicationContext启动工作大致归纳下有以下5大步骤

上面的12大步骤太长, 先归纳一下, 变成 5个步骤进行介绍。

AbstractApplicationContext#refresh() 方法是 Spring 容器启动方法,负责初始化上下文,加载/配置 BeanFactory,注册后处理器,实例化单例 Bean,初始化事件机制,最终完成容器启动并发布刷新事件。

ioc容器ApplicationContext启动工作大致归纳下有以下5大步骤

(1)准备阶段

  • 设置容器状态(激活/未激活)并初始化环境变量(Environment

  • 准备早期事件监听器,缓存启动期事件(如 ContextRefreshedEvent

(2)Bean定义加载与注册

  • 资源定位‌:解析配置文件(XML/注解/Java配置)为 Resource 对象。
  • BeanDefinition解析‌:通过 BeanDefinitionReader 将资源转换为 BeanDefinition 对象。
  • 注册到容器‌:存储到 BeanDefinitionMapDefaultListableBeanFactory 内部实现)。

‌**(3)后处理与扩展**‌

  • 调用 BeanFactoryPostProcessor 修改 Bean 定义(如占位符解析)。
  • 注册 BeanPostProcessor(如 @Autowired 处理器)。

‌**(4)Bean实例化与依赖注入**‌

  • 预实例化非懒加载单例 Bean,完成属性注入和初始化(@PostConstruct
  • 处理循环依赖(通过三级缓存机制)

‌**(5)容器启动完成**‌

  • 发布 ContextRefreshedEvent 事件,触发监听器逻辑
  • 启动生命周期组件(如 LifecycleProcessor

容器启动的入口

IOC容器启动入口,都是调用AbstractApplicationContext#refresh() 方法

Spring 根据应用类型选择不同的 ApplicationContext 实现类,但最终都会调用父类 AbstractApplicationContextrefresh() 方法:

Context 实现类触发 refresh() 的时机配置方式
ClassPathXmlApplicationContext构造时自动调用 或 手动调用 refresh()XML 配置文件
XmlWebApplicationContextContextLoaderListener 初始化时触发XML + web.xml
AnnotationConfigApplicationContextSpringApplication.refreshContext() 调用注解(@Configuration
AnnotationConfigServletWebServerApplicationContext同上,自动启动内嵌服务器(Tomcat/Jetty)注解 +application.properties
spriing boot应用

xml配置的spring应用 :ClassPathXmlApplicationContext

image-20250617122342070

注解的spring应用:AnnotationConfigApplicationContext

image-20250617122438057

AbstractApplicationContext#refresh() 中容器启动的12大步骤非常重要,总结下:

(1) prepareRefresh() - 准备刷新: 初始化启动标志、属性源校验、早期事件集合

(2) obtainFreshBeanFactory() - 获取新BeanFactory 创建/刷新BeanFactory,加载Bean定义,XML/注解配置解析、Bean定义注册发生在这里

(3) prepareBeanFactory() - 配置标准BeanFactory:设置类加载器、注册标准PostProcessor(ApplicationContextAwareProcessor)

(4) postProcessBeanFactory() - 后处理BeanFactory:子类扩展点,修改Bean定义,比如Web容器注册Servlet相关处理器

(5) invokeBeanFactoryPostProcessors() - 执行工厂后处理器​​:@Configuration解析、@Value(${url.jdbc})占位符注入

(6) registerBeanPostProcessors() - 注册Bean后处理器​:AOP代理创建、@Autowired注入

(7) initMessageSource() - 初始化国际化

(8) initApplicationEventMulticaster() - 初始化事件广播器

(9) onRefresh() - 子类扩展刷新:模板方法供子类扩展,Spring Boot启动内嵌服务器

(10) registerListeners() - 注册监听器

(11) finishBeanFactoryInitialization() - 完成单例初始化:bean从这里创建

(12) finishRefresh() - 完成刷新

容器启动的时序图:

AbstractApplicationContext#refresh() 源码如下:


@Override
public void refresh() throws BeansException, IllegalStateException {
    // 使用同步锁确保上下文刷新操作的原子性,防止多线程并发刷新
    synchronized (this.startupShutdownMonitor) {
        // 记录上下文刷新的启动步骤,用于性能监控和分析(Spring 5.3+ 新增功能)
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

        // 第一步:准备刷新上下文环境
        // 设置启动日期、激活状态标记,初始化属性源,验证必填属性
        prepareRefresh();

        // 第二步:获取刷新后的 BeanFactory
        // 通常是创建一个新的 BeanFactory 实例,并加载 Bean 定义
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 第三步:配置 BeanFactory 的标准上下文特征
        // 设置类加载器、表达式解析器、注册 BeanPostProcessor 等
        prepareBeanFactory(beanFactory);

        try {
            // 第四步:允许子类对 BeanFactory 进行后置处理
            // 例如:PropertySourcesPlaceholderConfigurer 替换占位符
            postProcessBeanFactory(beanFactory);

            // 记录 Bean 后置处理的启动步骤
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            
            // 第五步:调用已注册的 BeanFactoryPostProcessor
            // 这些处理器可以修改 Bean 定义,例如 PropertySourcesPlaceholderConfigurer
            invokeBeanFactoryPostProcessors(beanFactory);

            // 第六步:注册 BeanPostProcessor
            // 这些处理器将在 Bean 创建过程中执行额外处理(如 AOP 代理)
            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();

            // 第七步:初始化 MessageSource 用于国际化支持
            // 配置和初始化用于解析消息的组件
            initMessageSource();

            // 第八步:初始化 ApplicationEventMulticaster
            // 配置事件广播器,用于发布应用事件
            initApplicationEventMulticaster();

            // 第九步:特定上下文子类的特殊 Bean 初始化
            // 例如,WebApplicationContext 会在这里初始化 Servlet 相关的 Bean
            onRefresh();

            // 第十步:注册事件监听器
            // 查找并注册所有实现了 ApplicationListener 接口的 Bean
            registerListeners();

            // 第十一步:实例化所有剩余的非懒加载单例 Bean
            // 完成所有剩余 Bean 的创建和依赖注入
            finishBeanFactoryInitialization(beanFactory);

            // 第十二步:完成刷新过程,发布上下文刷新事件
            // 初始化生命周期处理器,调用所有实现了 Lifecycle 接口的 Bean 的 start() 方法
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // 发生异常时销毁已创建的单例 Bean,避免资源泄漏
            destroyBeans();

            // 重置 'active' 标志,取消刷新操作
            cancelRefresh(ex);

            // 将异常传播给调用者
            throw ex;
        }

        finally {
            // 重置 Spring 核心中的常见内省缓存
            // 例如,类型匹配缓存、方法参数缓存等
            resetCommonCaches();
            contextRefresh.end();
        }
    }
}

这里关键是容器启动的12大步骤,分别分析下

1 prepareRefresh 准备上下文环境

prepareRefresh() 初始化容器状态,设置启动时间及激活标志,加载属性源并校验必需配置,备份事件监听器并收集早期事件,为后续 Bean 加载和初始化流程奠定基础。

源码:


/**
 * Prepare this context for refreshing, setting its startup date and
 * active flag as well as performing any initialization of property sources.
 */
protected void prepareRefresh() {
	// 1. 设置容器启动时间和激活状态
	//    - 记录当前时间作为启动时间
	//    - 标记容器为非关闭状态(closed=false)和激活状态(active=true)
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);

	// 2. 调试日志记录
	//    输出容器刷新信息(trace/debug级别)
	if (logger.isDebugEnabled()) {
		if (logger.isTraceEnabled()) {
			logger.trace("Refreshing " + this);
		}
		else {
			logger.debug("Refreshing " + getDisplayName());
		}
	}

	// 3. 初始化属性源
	//    允许子类自定义占位符属性源(如从配置文件加载)
	initPropertySources();

	// 4. 验证必需属性是否可解析
	//    确保所有标记为必须的属性在环境中存在且可解析
	//    例如:@Value("${required.prop}") 中的 required.prop 必须存在
	getEnvironment().validateRequiredProperties();

	// 5. 处理事件监听器
	//    - 如果尚未保存早期监听器,则备份当前监听器
	//    - 否则将当前监听器重置为早期状态
	//    用于保证在 refresh 过程中事件监听器的稳定性
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		// Reset local application listeners to pre-refresh state.
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// 6. 初始化早期事件集合
	//    收集 refresh 阶段前触发的事件
	//    这些事件将在事件广播器初始化完成后统一发布
	//    例如:EnvironmentChangeEvent 等
	//    (因为事件广播器尚未初始化,此时无法直接发布)
	this.earlyApplicationEvents = new LinkedHashSet<>();
}

这个方法就像是在搭建一个舞台,确保所有准备工作都到位了,才能让后面的“演员”(Bean)顺利登场。

(1) 记录启动时间和状态

首先,它会记录下当前的时间,作为容器的启动时间。同时,把容器的状态设置为“已启动”和“正在运行”。这就像是给舞台打上灯光,告诉大家表演即将开始。

(2) 打印日志信息

如果开启了调试模式,它会输出一些日志信息,告诉开发者容器正在刷新。这就好比后台工作人员在提醒大家:“舞台准备中,请稍等。”

(3) 加载配置文件

接下来,它会去初始化属性源,也就是从配置文件里读取一些必要的参数。你可以把它想象成检查剧本,确保每个角色都有台词。

(4) 验证配置是否正确

然后,它会检查配置文件里的关键参数是否存在。如果某个参数是必须的,但没有找到,就会报错。这就像是在确认剧本里的重要情节有没有遗漏。

(5) 备份事件监听器

它还会备份当前的事件监听器,确保在刷新过程中不会丢失任何重要的事件监听功能。这就像在演出前,先把所有的道具和服装清点一遍,以免出错。

(6) 收集早期事件

最后,它会收集一些在刷新阶段之前触发的事件,等到事件广播器准备好后再统一发布。这就像是在彩排时记录下演员的临时调整,等正式演出时再统一执行。

2 obtainFreshBeanFactory 创建工厂

这个方法主要是创建了一个“工厂”叫BeanFactory,并且把配置文件里的内容解析出来,加载到内存中,注册成一个个Bean定义对象。

AbstractApplicationContext的obtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程,代码如下:


protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //这里就是模版模式的钩子方法,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
    refreshBeanFactory();
    return getBeanFactory();
}

AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,如下:


//org.springframework.context.support.AbstractApplicationContext#refreshBeanFactory
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

容器真正调用的是其子类AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法;在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。方法的源码如下:


/**
 * 刷新BeanFactory的核心方法:
 * 1. 销毁现有BeanFactory及其管理的所有Bean
 * 2. 创建新的BeanFactory实例
 * 3. 加载Bean定义配置
 */
protected final void refreshBeanFactory() throws BeansException {
    // 如果已存在BeanFactory,则先销毁
    if (hasBeanFactory()) {
        destroyBeans();      // 销毁所有已创建的Bean实例
        closeBeanFactory();  // 关闭当前BeanFactory
    }
    
    try {
        // 创建新的默认BeanFactory(核心容器实现)
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 设置序列化ID(用于分布式环境)
        beanFactory.setSerializationId(getId());
        // 定制化BeanFactory(子类可扩展)
        customizeBeanFactory(beanFactory);
        // 加载Bean定义(XML/注解等配置源)
        // 这里又是模版模式的钩子方法,具体实现在子类
        loadBeanDefinitions(beanFactory);
        // 将新创建的BeanFactory赋值给当前应用上下文
        this.beanFactory = beanFactory;
    }
    catch (IOException ex) {
        // 处理配置加载时的IO异常
        throw new ApplicationContextException(
            "I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}


这里loadBeanDefinitions非常重要,负责Bean定义的加载,下面分析下

2.1 loadBeanDefinitions加载Bean定义

加载 Bean 定义的过程,用到了一种叫“模板设计模式”的方法。

首先,在 AbstractRefreshableApplicationContext 这个类里定义了一个模板方法(#refreshBeanFactory)和一个钩子方法(#loadBeanDefinitions)。

钩子方法的具体实现是由它的子类来完成的。比如:

  • 如果是通过 XML 文件加载 Bean 定义,就由 AbstractXmlApplicationContext#loadBeanDefinitions 来实现。
  • 如果是通过注解(比如 @Configuration)来加载 Bean 定义,就由 AnnotationConfigWebApplicationContext#loadBeanDefinitions 来实现。
类名加载方式核心组件
AbstractRefreshableApplicationContext抽象模板定义抽象方法 loadBeanDefinitions
AbstractXmlApplicationContextXML 文件XmlBeanDefinitionReader
AnnotationConfigWebApplicationContextJava 注解(@ConfigurationAnnotatedBeanDefinitionReader

image-20250616104925908

AnnotationConfigWebApplicationContext#loadBeanDefinitions注解实现


protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    // 创建注解读取器和扫描器
    AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
    ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
    
    // 配置读取器和扫描器(如环境、注解过滤器等)
    // ...
    
    // 注册配置类(如 @Configuration 类)
    if (this.annotatedClasses != null) {
        reader.register(this.annotatedClasses);
    }
    
    // 扫描包路径(如 @ComponentScan 指定的包)
    if (this.basePackages != null && this.basePackages.length > 0) {
        scanner.scan(this.basePackages);
    }
    
    // 处理 XML 配置文件(如果启用)
    // ...
}

  • 使用 AnnotatedBeanDefinitionReader 注册 @Configuration 类。
  • 使用 ClassPathBeanDefinitionScanner 扫描包路径,识别 @Component@Service 等注解的类。

AbstractXmlApplicationContext#loadBeanDefinitions中xml实现


protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // 创建 XML 读取器
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // 配置读取器环境(如资源加载器、实体解析器等)
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    // 初始化读取器(可被子类覆盖)
    initBeanDefinitionReader(beanDefinitionReader);
    // 从资源(XML 文件)加载 Bean 定义
    loadBeanDefinitions(beanDefinitionReader);
}

  • 创建 XmlBeanDefinitionReader 解析 XML 文件。
  • 通过 loadBeanDefinitions(beanDefinitionReader) 定位并加载 XML 资源(如 contextConfigLocation)。

注意:这里AnnotatedBeanDefinitionReader和XmlBeanDefinitionReader,使用的是委托模式

注‌:模板方法模式‌与‌委托模式‌的核心区别:

  1. ‌实现方式‌:模板方法通过‌继承‌定义算法骨架(父类控制流程,子类实现细节),如Spring的refresh();委托模式通过‌组合‌将任务转交给其他对象(如DispatcherServlet委派请求)。
  2. ‌关注点‌:模板方法强调‌流程复用‌,委托模式侧重‌任务分发‌。
  3. ‌灵活性‌:委托模式更易动态替换执行者,模板方法需修改子类扩展流程。

这里具体解析xml和注解的过程不再分析,无非就是通过SAX XML解析器,注解解析器AnnotatedBeanDefinitionReader,拿到BeanDefinition

2.2 解析过后的BeanDefinition在IoC容器中的注册

Bean定义对象的注册方法的调用触发时机是:

  • XML配置方式:

在容器启动时,XmlBeanDefinitionReader解析XML文件,遇到每个<bean>标签时立即调用registerBeanDefinition(),同步完成所有静态注册。

  • 注解配置方式:分三阶段触发:

(1)组件扫描ClassPathBeanDefinitionScanner发现@Component类时注册;

(2)配置类处理ConfigurationClassPostProcessor解析@Bean方法时动态注册;

(3)扩展机制:通过ImportBeanDefinitionRegistrar编程式注册。

注册的具体过程

当Bean定义被解析后,会生成一个BeanDefinitionHolder对象(它封装了Bean定义的相关信息)。

接着,调用BeanDefinitionReaderUtils中的registerBeanDefinition方法,把这个Bean定义注册到IoC容器中。

完整的流程是: 当Bean定义被解析后,得到封装 BeanDefinition 的 BeanDefinitionHolder对象,然后调用 BeanDefinitionReaderUtils 的 registerBeanDefinition 方法向IoC容器注册解析的Bean,

BeanDefinitionReaderUtils的注册的源码如下:


// 通过BeanDefinitionRegistry将BeanDefinitionHolder注册到BeanFactory
public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
        throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正完成注册功能的是DefaultListableBeanFactory。

真正完成注册的是谁?

虽然上面提到BeanDefinitionReaderUtils负责调用注册方法,但真正执行注册功能的是DefaultListableBeanFactory

IoC容器本质上就是一个“大仓库”,内部用了一个Map来存储所有的Bean定义。

每个Bean都有一个唯一的名称作为键,对应的Bean定义作为值。简单来说,注册的过程就是把Bean定义放进这个“大仓库”里。

IOC容器本质上就是一个beanDefinitionMap, 注册即将BeanDefinition put到map中

下面是具体的实现代码:


/**
 * 存储所有 Bean 的原始定义(BeanDefinition),键为 Bean 名称。
 * <p>
 * - 该 Map 在容器注册阶段填充,每个 Bean 名称对应一个 BeanDefinition 对象。
 * - 使用 ConcurrentHashMap 确保线程安全,支持并发注册和访问。
 */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

/**
 * 存储已合并的 BeanDefinitionHolder,键为 Bean 名称。
 * <p>
 * - 当 BeanDefinition 需要继承父 Bean 或合并配置时,生成合并后的 BeanDefinition。
 * - BeanDefinitionHolder 包含合并后的 BeanDefinition、别名(aliases)等元数据。
 * - 使用 ConcurrentHashMap 确保线程安全,支持并发访问。
 */
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {

    // 校验beanName和beanDefinition非空
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    // 对AbstractBeanDefinition子类进行额外校验
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                    "Validation of bean definition failed", ex);
        }
    }

    // 检查是否已存在同名BeanDefinition
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        // 不允许覆盖时抛出异常
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        // 框架生成的BeanDefinition覆盖用户定义的BeanDefinition时记录日志
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (logger.isInfoEnabled()) {
                logger.info("Overriding user-defined bean definition for bean '" + beanName +
                        "' with a framework-generated bean definition: replacing [" +
                        existingDefinition + "] with [" + beanDefinition + "]");
            }
        }
        // 不同定义的覆盖行为记录调试日志
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Overriding bean definition for bean '" + beanName +
                        "' with a different definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        // 相同定义的覆盖行为记录跟踪日志
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Overriding bean definition for bean '" + beanName +
                        "' with an equivalent definition: replacing [" + existingDefinition +
                        "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        // 容器启动后注册需同步处理
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 更新beanDefinitionNames列表保证迭代稳定性
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        // 启动阶段直接注册
        else {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    // 重置相关缓存
    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        clearByTypeCache();
    }
}


至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。

现在IoC容器中已经建立了整个Bean的配置信息,这些 BeanDefinition 信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。

这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

如果是加载xml的bean定义,BeanDefinition的加载和注册流程总结如下:

img

3 prepareBeanFactory 准备Bean工厂

prepareBeanFactory 用于配置 ConfigurableListableBeanFactory 的基础特性。它设置类加载器、表达式解析器,注册资源编辑器,标准的后置处理器(比如(ApplicationContextAwareProcessor),处理特殊 Aware 接口,配置依赖解析规则,注册核心环境 Bean(如 Environment),为 Bean 实例化做准备。

这个方法就像一个“装修师傅”,负责把 BeanFactory 的“房子”布置好,让里面的“家具”(Bean)可以正常运作。具体做了以下几件事:

(1) 设置类加载器

就像告诉 BeanFactory 用哪个工具去找到需要的类文件。代码里是通过 getClassLoader() 来设置的。

(2) 配置表达式解析器

如果允许使用 SpEL 表达式(类似于一种动态计算的小工具),就给 BeanFactory 配上一个解析器,让它能理解这些表达式。

(3) 注册资源编辑器

这是为了让 BeanFactory 能处理 Resource 类型的属性。比如,如果你有一个文件路径,它能帮你正确转换成对应的资源对象。

(4) 添加后置处理器

后置处理器就像是“管家”,负责在 Bean 创建前后做一些额外的工作。这里加了一个 ApplicationContextAwareProcessor,它会帮 Bean 注入一些特殊的接口实现,比如 EnvironmentAware 等。

(5) 忽略某些接口的自动注入

因为前面的“管家”已经处理了这些接口,所以这里告诉 BeanFactory 不要再去管它们了。比如 EnvironmentAwareResourceLoaderAware 等。

(6) 注册可解析依赖项

注册可解析依赖项,使 BeanFactory、ResourceLoader 等接口可被自动装配

(7) 检测并注册事件监听器

添加了一个 ApplicationListenerDetector,用来检查是否有 Bean 是事件监听器,并把它注册好。

(8) 支持加载时织入

如果当前环境不是原生镜像,并且有织入器(类似于动态修改类的功能),就配置相关的支持。这包括添加一个织入器感知处理器,以及设置临时类加载器。

(9) 注册默认的环境 Bean

如果还没有定义 environmentsystemPropertiessystemEnvironment 这些核心环境 Bean,就直接注册它们。这样其他 Bean 可以方便地使用这些信息。


/**
 * 配置 BeanFactory 的标准上下文特性,例如类加载器、表达式解析器、后处理器等。
 * 该方法为 BeanFactory 注册 Spring 容器的核心功能支持。
 *
 * @param beanFactory 需要配置的 ConfigurableListableBeanFactory 实例
 */
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 1. 设置 BeanFactory 的类加载器为当前上下文的类加载器
    beanFactory.setBeanClassLoader(getClassLoader());
    
    // 2. 注册 SpEL 表达式解析器(如果未禁用 SpEL)
    if (!shouldIgnoreSpel) {
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    }
    
    // 3. 注册资源编辑器注册器,支持 Resource 类型的属性转换
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 4. 添加 ApplicationContextAwareProcessor 后处理器
    // 该处理器负责注入 EnvironmentAware、ResourceLoaderAware 等接口的实现类
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    
    // 5. 忽略以下接口的自动依赖注入,因为它们由 ApplicationContextAwareProcessor 处理
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
    beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

    // 6. 注册可解析依赖项,使 BeanFactory、ResourceLoader 等接口可被自动装配
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // 7. 添加 ApplicationListenerDetector 后处理器
    // 检测并注册内部 Bean 中的 ApplicationListener
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

    // ------------------------ 处理加载时织入 ------------------------
    // 8. 非原生镜像环境且存在织入器时,配置加载时织入支持
    if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        // 添加织入器感知处理器(用于注入 LoadTimeWeaver)
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // 设置临时类加载器(用于类型匹配)
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // 9. 注册默认的环境Bean
    if (!beanFactory.containsLocalBean("environment")) {
        beanFactory.registerSingleton("environment", this.getEnvironment());
    }

    if (!beanFactory.containsLocalBean("systemProperties")) {
        beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
    }

    if (!beanFactory.containsLocalBean("systemEnvironment")) {
        beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
    }

}

这个方法的核心就是给 BeanFactory 配置好各种功能,让它能顺利地管理 Bean。

可以把它想象成一个“准备工作清单”,每一步都是为了让 Spring 容器运行得更顺畅。

4 postProcessBeanFactory 子类扩展BeanFactory

postProcessBeanFactory方法,允许子类在BeanFactory配置完成后(如设置类加载器、表达式解析器后)进行自定义处理,例如添加Web组件、注册作用域或修改Bean定义,是扩展容器功能的关键入口。

或者说,postProcessBeanFactory 方法就像是一个“插槽”,它让子类可以在 BeanFactory 配置完成后,再做一些额外的定制化操作。比如,可以往容器里加一些专门的组件,或者调整 Bean 的定义。这个方法是扩展 Spring 容器功能的一个重要入口。


protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}	

举个例子,在 Spring MVC 中,AbstractRefreshableWebApplicationContext 类重写了这个方法,专门为 Web 环境做了适配。


/**
 * 在标准初始化后修改应用程序上下文的内部bean工厂。
 * 所有bean定义已加载但未实例化,用于注册Web环境特有的处理器和作用域
 * 
 * 主要功能:
 * 1. 注册Servlet环境处理器
 * 2. 配置Web作用域
 * 3. 注册环境Bean
 */
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 1. 注册ServletContextAwareProcessor后处理器
    // 用于向实现了ServletContextAware/ServletConfigAware的Bean注入Servlet相关对象
    beanFactory.addBeanPostProcessor(
        new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    
    // 2. 忽略自动装配接口
    // 防止容器尝试自动解析ServletContextAware/ServletConfigAware接口
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

    // 3. 注册Web作用域(request/session/application等)
    // 使Bean能使用@Scope("request")等Web特有作用域
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    
    // 4. 注册环境Bean
    // 将ServletContext/ServletConfig注册为可注入的Bean
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}


功能解释

(1) 注册 Servlet 相关的后处理器

就像是给每个 Bean 配了一个“助手”,这个助手能帮 Bean 找到并注入 Servlet 相关的对象(比如 ServletContext)。这样,如果某个 Bean 需要用到这些对象,就不用自己去手动获取了。

(2) 忽略某些接口

这就好比告诉容器:“别瞎猜,不是所有 Bean 都需要 Servlet 相关的东西。” 这样可以避免不必要的错误。

(3) 注册 Web 特有的作用域

想象一下,不同的 Bean 可能在不同的时间范围内存在,比如只在一次请求中有效(@Scope("request")),或者在整个会话期间都有效(@Scope("session"))。这里就是把这些作用域加到容器里,方便后续使用。

(4) 注册环境相关的 Bean

最后一步是把 ServletContextServletConfig 注册成普通的 Bean。这样,其他 Bean 如果需要它们,就可以直接通过依赖注入来获取,而不用手动去找。

简单来说,postProcessBeanFactory 方法就是给开发者提供了一个机会,在 BeanFactory 配置完成后,再根据需要做些额外的事情。在 Web 环境下,Spring 利用这个方法做了很多和 Servlet 相关的准备工作,让整个系统更贴合 Web 场景的需求。

5 invokeBeanFactoryPostProcessors 执行增强的方法

invokeBeanFactoryPostProcessors 这个方法,主要是用来按顺序执行一些特殊的“处理器”。这些处理器可以帮我们调整 Spring 容器里的配置信息。

简单来说,它会先处理那些能注册新东西的处理器(比如新增 Bean 定义),然后再处理那些只能修改已有东西的处理器(比如调整 Bean 的属性)。整个过程支持按照优先级来排序,确保每个处理器都能在正确的时间点工作。

具体来说 invokeBeanFactoryPostProcessors,负责按优先级顺序执行所有BeanFactoryPostProcessor。先处理BeanDefinitionRegistryPostProcessor实现类(注册新定义),再处理普通BeanFactoryPostProcessor(修改现有定义),支持PriorityOrdered/Ordered排序控制执行顺序,最终完成容器配置元数据的最终调整。


/**
 * 实例化并调用所有已注册的 BeanFactoryPostProcessor 后置处理器,
 * 若指定了顺序,则按顺序执行。
 * <p>必须在单例 Bean 实例化之前调用此方法。
 */
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 委托给 PostProcessorRegistrationDelegate 执行所有 BeanFactoryPostProcessor
    // 包括 BeanDefinitionRegistryPostProcessor(可修改 Bean 定义)
    // 和普通 BeanFactoryPostProcessor(可修改 BeanFactory)
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // 检测 LoadTimeWeaver(加载时织入器)并配置相关处理
    // 若此时发现 LoadTimeWeaver Bean(例如通过 ConfigurationClassPostProcessor 注册的 @Bean 方法)
    if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && 
        beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        // 添加 LoadTimeWeaverAwareProcessor 后置处理器,用于处理实现 LoadTimeWeaverAware 接口的 Bean
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // 设置临时类加载器,用于类型匹配(处理类加载时的字节码转换)
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

这个方法的核心任务是:在创建单例 Bean 之前,调用所有已经注册的“后置处理器”。这些后置处理器可以对容器的配置进行最后的调整。

这里的钩子方法有两个接口:

  • BeanFactoryPostProcessor:可修改 BeanFactory 或 Bean 定义。就像是装修房子时,调整一下家具的位置或者颜色。
  • BeanDefinitionRegistryPostProcessor(前者的子接口):可直接注册新的 Bean 定义。不仅可以修改现有定义,还能直接往容器里添加新的 Bean 定义。比喻:除了调整家具,还可以往房子里添置新家具。
特性BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor
核心接口BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor
执行时机Bean 定义加载完成后先于 BeanFactoryPostProcessor 执行
主要用途修改现有 Bean 定义注册新的 Bean 定义
典型场景属性替换、修改 Bean 配置动态扫描注册、条件注册
内置实现PropertySourcesPlaceholderConfigurerConfigurationClassPostProcessor

PropertySourcesPlaceholderConfigurer:Spring用于解析${}占位符的处理器,将外部属性文件/环境变量注入到Bean定义中。
ConfigurationClassPostProcessor:Spring处理@Configuration类的核心处理器,负责解析@Bean@ComponentScan等注解生成Bean定义。

通过 invokeBeanFactoryPostProcessors 方法,Spring 容器可以在启动时灵活地调整配置信息。

无论是修改现有的 Bean 定义,还是动态注册新的 Bean,都可以通过这两个接口实现。这就好比装修房子时,既可以选择调整现有的家具布局,也可以选择购买新的家具来丰富房间的功能。

BeanFactoryPostProcessor 应用场景

(1)PropertySourcesPlaceholderConfigurer属性占位符替换

从配置文件加载属性值,替换 Bean 定义中的占位符(如 ${db.url}


@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

简单来说,这个功能就是从配置文件里读取一些值,然后把这些值填到代码里的占位符中。比如 ${db.url} 这种东西,其实就是个“占位符”,最后会被替换成真实的数据库地址。

举个例子,就像 写作文时先用“XXX”占着位置,等后来再把具体的名字填进去。

(2)动态修改 Bean 定义

有时候我们希望在程序运行的时候,调整一些 Bean 的设置,比如改变它的属性值、让它延迟加载(懒加载),或者调整它的作用范围。

修改现有 Bean 的属性值、作用域或懒加载配置,比如:将所有 Service Bean 设置为懒加载,这样它们不会一开始就占用资源。

下面是实现的代码:


public class LazyServiceProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
        for (String beanName : factory.getBeanDefinitionNames()) {
            BeanDefinition def = factory.getBeanDefinition(beanName);
            if (def.getBeanClassName().endsWith("Service")) {
                def.setLazyInit(true);
            }
        }
    }
}

(3)集成外部配置源

除了从普通的配置文件读取数据,我们还可以从其他地方获取配置信息,比如 Redis 或 ZooKeeper 这些工具。这就像是你不仅可以从家里的书架上找书,还可以去图书馆借书一样。

例如, 从 Redis、ZooKeeper 等非标准源加载配置。 可以从 Redis 里动态获取数据库的 URL 地址,然后把它填到程序里。下面是实现的代码:


  public class RedisConfigProcessor implements BeanFactoryPostProcessor {
      @Override
      public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
          BeanDefinition dsDef = factory.getBeanDefinition("dataSource");
          dsDef.getPropertyValues().add("url", redisClient.get("db.url"));
      }
  }

(5)处理自定义注解

有时候我们会自己定义一些注解,用来给代码增加特殊的功能。比如,我们定义了一个叫 @CustomScope 的注解,它可以指定某个 Bean 的作用范围(比如是全局的还是局部的)。

比如: 解析自定义注解并修改 Bean 定义。下面的代码会检查每个 Bean 是否用了这个 @CustomScope 注解,如果用了,就按照注解里的值来设置作用范围:


public class CustomScopeProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) {
        for (String name : factory.getBeanDefinitionNames()) {
            BeanDefinition def = factory.getBeanDefinition(name);
            Class<?> clazz = Class.forName(def.getBeanClassName());
            if (clazz.isAnnotationPresent(CustomScope.class)) {
                def.setScope(clazz.getAnnotation(CustomScope.class).value());
            }
        }
    }
}

BeanDefinitionRegistryPostProcessor 应用场景

(1)动态注册 Bean 定义

运行时动态添加 Bean 定义,无需硬编码。,比如:注册自定义健康检查 Bean:


public class HealthCheckRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        RootBeanDefinition def = new RootBeanDefinition(MyHealthCheck.class);
        registry.registerBeanDefinition("healthCheck", def);
    }
}

(2)条件注册 Bean

根据运行时条件决定是否注册 Bean。比如:仅在生产环境注册监控 Bean:


public class MonitoringRegistrar implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (isProductionEnvironment()) {
            registry.registerBeanDefinition("metricsExporter", new RootBeanDefinition(MetricsExporter.class));
        }
    }
}

6 registerBeanPostProcessors 注册BeanPostProcessor

registerBeanPostProcessors(beanFactory) ,用于注册所有 BeanPostProcessor 实现类。

它按优先级(PriorityOrderedOrdered、普通)分类并注册到 BeanFactory,确保在后续 Bean 实例化前后调用其扩展逻辑(如属性注入、AOP 代理等)。

首先拿到工厂中所有的BeanPostProcessor类型的Bean,然后分类处理,排序注册。

注意:

  • 这个方法只注册BeanPostProcessor,不执行

  • 而上面的方法直接执行了BeanFactoryPostProcessor

registerBeanPostProcessors(beanFactory) 这个方法的作用,就是把所有 BeanPostProcessor 类型的组件注册到 Bean 工厂里。

可以把它理解成给工厂安排了一些“质检员”,这些质检员会在生产产品(也就是创建 Bean)的过程中,帮忙检查或者修改产品。

具体来说,这些“质检员”会按照优先级分成三类:第一类是“特别重要”的(PriorityOrdered),第二类是“比较重要”的(Ordered),第三类是普通的。分好类之后,再按顺序注册到工厂里,确保它们能在合适的时间介入,比如在 Bean 创建之前或之后做一些额外的操作(比如给 Bean 添加一些属性,或者给它套上一层“外衣”实现 AOP 功能)。

BeanPostProcessor和BeanFactoryPostProcessor的区别

对比项BeanPostProcessorBeanFactoryPostProcessor
核心接口BeanPostProcessorBeanFactoryPostProcessor
作用对象干预:Bean 实例干预:Bean 定义 或 BeanFactory
执行时机Bean 实例化后、初始化前后Bean 定义加载后、实例化前
典型场景AOP 代理生成、属性修改、依赖注入增强配置文件解析、动态修改 Bean 定义
内置实现举例AutowiredAnnotationBeanPostProcessorPropertySourcesPlaceholderConfigurer
扩展方式实现 postProcessBeforeInitialization
postProcessAfterInitialization方法
实现 postProcessBeanFactory方法
影响范围单个 Bean 实例全局 Bean 定义或 BeanFactory 配置

注:

  • AutowiredAnnotationBeanPostProcessor:处理 @Autowired@Value@Inject 注解的 Bean 后处理器,负责自动注入依赖
  • PropertySourcesPlaceholderConfigurer:解析 Bean 定义中 ${...} 占位符的 BeanFactory 后处理器,从属性源(如配置文件)加载实际值
  • AnnotationAwareAspectJAutoProxyCreator:产生AOP代理的BeanPostProcessor

用大白话介绍一下:

(1) BeanPostProcessor

  • 好比是“豆子装修工”,等豆子造好了,还没完全准备好时,它来帮豆子打扮一下,比如给它加个代理、改改属性。
  • 比如 AutowiredAnnotationBeanPostProcessor,它的任务就是看到 @Autowired 这种注解时,自动把对应的依赖塞进去。

(2) BeanFactoryPostProcessor

  • 好比是“豆子图纸修改师”,在豆子还没开始造的时候,它先去看看图纸(也就是豆子的定义),如果有需要就改一改。
  • 比如 PropertySourcesPlaceholderConfigurer,它的任务是把配置文件里的值(比如 ${db.url})替换到豆子定义里去。

(3) 执行顺序

  • BeanFactoryPostProcessor 是最早介入的,它在豆子还没开始造的时候就动手了。
  • BeanPostProcessor 是稍晚一些,等豆子已经造出来了,但它还没完全准备好时再动手。

(4) 影响范围

  • BeanPostProcessor 只能动一个具体的豆子。
  • BeanFactoryPostProcessor 可以动所有的豆子定义,甚至可以改整个工厂的配置。

希望这样解释更清楚啦!

7 initMessageSource 国际化消息

initMessageSource 的作用是设置一个叫“国际化消息源”的东西(也就是 MessageSource)。简单来说,它帮我们管理不同语言的文本内容,比如中文、英文等。

它会先看看系统里有没有已经配置好的 messageSource 这个组件。如果有的话,就直接用;如果没有,就会创建一个默认的 DelegatingMessageSource。这个东西就像是一个“翻译官”,能根据你提供的资源文件(比如 messages.properties),把里面的键值对找出来,然后帮你换成对应的文本内容。

另外,它还能处理父子容器之间的关系。比如,父容器有一些默认的语言配置,子容器也可以继承这些配置,或者自己再加一些新的内容。这样就能方便地支持多语言的加载和解析。


// 这里的代码可以作为参考,不需要改写
if (this.messageSource == null) {
    DelegatingMessageSource delegatingMessageSource = new DelegatingMessageSource();
    // 设置父消息源
    if (this.parentMessageSource != null) {
        delegatingMessageSource.setParentMessageSource(this.parentMessageSource);
    }
    this.messageSource = delegatingMessageSource;
}

8 initApplicationEventMulticaster 初始化事件多播器

创建了一个多播器,为添加Listener提供支持。

主要逻辑:

  • 容器中是否存在applicationEventMulticaster,如果存在直接注册
  • 如果不存在,创建一个SimpleApplicationEventMulticaster,注册到容器中。

/**
 * 初始化应用事件多播器(ApplicationEventMulticaster)。
 * 1. 检查容器是否已定义自定义的 ApplicationEventMulticaster Bean;
 * 2. 若存在则直接使用,否则创建默认的 SimpleApplicationEventMulticaster 并注册为单例。
 */
protected void initApplicationEventMulticaster() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        // 使用容器中已定义的自定义 ApplicationEventMulticaster
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
        }
    }
    else {
        // 创建默认的 SimpleApplicationEventMulticaster 并注册为单例
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
        if (logger.isTraceEnabled()) {
            logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                    "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
        }
    }
}

多播器是什么?

多播器就像一个“广播站”,它的任务是把消息发给所有感兴趣的人(也就是监听者)。如果没有这个广播站,消息就没法传递出去。

为什么要检查容器?

容器就像是一个“工具箱”,里面可能已经有人放了一个定制版的广播站。如果有现成的,我们就直接用;如果没有,就自己造一个简单的。

SimpleApplicationEventMulticaster 是什么?

这是一个默认的广播站,功能比较简单,但够用。

如果没人提供更高级的广播站,我们就用这个。

总结一下:这段代码的核心就是确保系统里有一个广播站,不管是别人提供的还是自己造的,都能正常工作。

9 onRefresh 扩展点

onRefresh() 是 Spring 容器刷新流程中的扩展点方法,在 refresh() 中调用,

onRefresh() 位于 BeanFactory 初始化后、单例 Bean 实例化前。

onRefresh() 用于子类执行容器级初始化逻辑(如启动 Web 服务器、注册监听器),默认为空实现,需子类重写自定义操作。

onRefresh()方法在Spring/SpringBoot中的典型应用场景包括:

‌**(1)Spring Boot内嵌Web服务器启动**‌

SpringBoot通过ServletWebServerApplicationContext子类重写该方法,自动创建并启动Tomcat/Jetty等内嵌服务器。

核心逻辑包含:


protected void onRefresh() {
    super.onRefresh();
    createWebServer(); // 触发Web服务器初始化
}

‌**(2)初始化Web相关组件**‌

Spring MVC在FrameworkServlet中利用该方法初始化DispatcherServlet,加载处理器映射(HandlerMapping)、视图解析器(ViewResolver)等Web层核心组件。

‌**(3)自定义容器扩展**


开发者可继承AbstractApplicationContext重写该方法,实现如定时任务调度、缓存预热等容器就绪后的自定义逻辑。

例如:


protected void onRefresh() {
    initScheduler(); // 初始化任务调度器
    loadCacheData(); // 预加载缓存数据
}

‌**(4)微服务注册触发**

在Spring Cloud场景中,部分框架会通过该方法在容器刷新完成后自动向注册中心(如Nacos)注册服务实例

该方法作为Spring扩展性的关键设计,允许子类在Bean初始化完成后、上下文刷新结束前插入定制化逻辑

10 registerListeners 注册事件监听

registerListeners() 是 Spring 事件机制里一个非常重要的初始化方法,它的主要任务就是把各种监听器准备好,方便后续处理事件。

这个方法可以分成三步来理解:

(1) 注册手动添加的静态监听器

这一步就像是你提前准备好的“哨兵”,Spring 会把这些“哨兵”安排到位,确保它们能第一时间发现并处理事件。

(2) 扫描并注册容器中所有ApplicationListener类型的Bean(延迟初始化)

Spring 容器里可能有很多不同类型的组件,这一步相当于在这些组件里,找那些专门负责监听事件的“特工”(也就是 ApplicationListener 类型的 Bean),然后把它们也加入到监听队伍中。

不过这里有个小技巧:这些“特工”不会马上被激活,而是等需要的时候再启动,这样可以避免影响其他组件的工作顺序。

(3) 处理早期缓存事件

处理早期缓存事件。该方法确保监听器完整注册并解决事件广播器未就绪时的时序问题,为后续事件发布提供支持。

有时候,在监听器还没完全准备好之前,就已经有一些事件发生了。这些事件会被暂时存起来,等到监听器就绪后,Spring 会把这些“漏网”的事件重新广播出去,确保没有遗漏。

image-20250616203229663

源码如下:


/**
 * 注册应用事件监听器(ApplicationListener)。
 * 1. **优先注册静态监听器(哨兵)**:通过 `getApplicationListeners()` 获取显式配置的监听器并注册;
 * 2. **注册监听器 Bean(特工)**:从容器中查找所有 `ApplicationListener` 类型的 Bean(不立即初始化,避免影响后处理器);
 * 3. **处理早期事件**:若存在未处理的早期事件(如容器启动时触发的事件),立即通过事件多播器广播。
 */
protected void registerListeners() {
    // 注册静态定义的监听器(显式配置的 ApplicationListener 实例)
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // 注册监听器 Bean(不立即初始化,避免影响后处理器的处理顺序)
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }

    // 处理早期事件(在事件多播器就绪后立即广播)
    Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
    this.earlyApplicationEvents = null;
    if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
        for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
            getApplicationEventMulticaster().multicastEvent(earlyEvent);
        }
    }
}

简单来说,这段代码的核心工作就是:

  • 先安排好手动配置的“哨兵”。
  • 再从容器里找到所有“特工”并加入队伍。
  • 最后处理那些提前发生但没来得及处理的事件。

希望这样的解释能让你更容易理解!

11 finishBeanFactoryInitialization 创建单例Bean

finishBeanFactoryInitialization 是 Spring 容器启动时最重要的一个方法,它的主要任务就是把那些需要提前创建的单例 Bean 给“造”出来。

这个过程可以简单理解为:Spring 把设计图(配置文件或注解)变成了实际可用的对象。

具体来说,它做了以下几件事:

  • 设置类型转换工具:初始化类型转换服务(ConversionService)处理类型转换。就像我们平时用计算器把人民币换成美元一样,Spring 也需要一个工具来处理不同类型之间的转换,比如把字符串转成日期。
  • 注册占位符解析器:注册默认占位符解析器支持@Value等注解。如果你在代码里用了类似 ${db.url} 这样的占位符,Spring 会自动帮你替换成真实的值,这就需要用到占位符解析器。
  • 提前初始化某些特殊 Bean:比如,提前初始化LoadTimeWeaverAware Bean确保AOP织入。有些 Bean 比较特别,比如和 AOP(面向切面编程)相关的,它们需要在其他 Bean 创建之前就准备好。
  • 冻结配置:冻结Bean定义配置防止运行时修改。Spring 把所有的 Bean 配置锁住,防止运行时被修改,这样可以保证系统的稳定性。
  • 实例化所有非延迟加载的单例 Bean:这是整个方法的核心部分,Spring 会通过 preInstantiateSingletons() 方法,把那些需要提前创建的单例 Bean 全部造出来,并完成依赖注入和初始化。

preInstantiateSingletons()`实例化所有非延迟单例Bean,这是非常重要的一个方法,触发Bean的完整的生命周期(创建→依赖注入→初始化)。同时该方法通过三级缓存解决循环依赖,是IOC容器从配置解析转向业务对象可用的关键转折点,体现了Spring"约定优于配置"的设计思想

finishBeanFactoryInitialization 的代码如下:


/**
 * 完成 BeanFactory 的最终初始化,实例化所有非懒加载的单例 Bean。
 * 这是 Spring 容器刷新(refresh())中最核心的步骤之一,负责将 Bean 定义转化为可用的 Bean 实例。
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 1. 初始化类型转换服务(ConversionService)
    // 若容器中存在名为 "conversionService" 且类型匹配的 Bean,则将其设置为全局转换服务
    // 用途:处理参数绑定、SpEL 表达式中的类型转换(如 String 转 Date)
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // 2. 注册默认的嵌入式值解析器(EmbeddedValueResolver)
    // 若容器中无自定义值解析器(如 PropertySourcesPlaceholderConfigurer),则注册默认解析器
    // 用途:解析注解中的占位符(如 @Value("${db.url}"))
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // 3. 提前初始化 LoadTimeWeaverAware 类型的 Bean
    // 目的:确保类加载期织入(AspectJ LTW)相关的转换器尽早注册
    // 注:此类 Bean 需在普通 Bean 实例化前初始化,以支持类加载时的切面织入[3,4](@ref)
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName); // 触发 Bean 的创建和初始化
    }

    // 4. 清理临时类加载器
    // 停止使用临时 ClassLoader(类型匹配阶段专用),释放资源[3](@ref)
    beanFactory.setTempClassLoader(null);

    // 5. 冻结 Bean 定义配置
    // 锁定所有 Bean 定义,禁止后续修改(如新增、删除 BeanDefinition)
    // 目的:提升后续实例化阶段的性能,并确保配置一致性[3,5](@ref)
    beanFactory.freezeConfiguration();

    // 6. 实例化所有非懒加载的单例 Bean(核心步骤)
    // 触发所有非 lazy-init 的单例 Bean 的创建、依赖注入、初始化回调(如 @PostConstruct)
    // 关键:解决循环依赖、执行 BeanPostProcessor 等均在此过程中完成
    beanFactory.preInstantiateSingletons();
}

该方法用于预实例化所有非懒加载的单例Bean。逻辑如下:

(1) 创建beanDefinitionNames的副本,防止初始化过程中修改影响遍历。

(2) 遍历所有Bean名称,获取其合并后的RootBeanDefinition。

(3) 若Bean是单例、非抽象、且非懒加载,则进行初始化:

  • 如果是FactoryBean,先判断是否为SmartFactoryBean并检查是否需要立即初始化;
  • 若满足条件或不是FactoryBean,则调用getBean()触发实例化。

(4) 保证在Spring容器启动时,所有符合条件的单例Bean被提前创建并完成依赖注入。

总结来说,finishBeanFactoryInitializationpreInstantiateSingletons() 是 Spring 容器启动时非常重要的两个方法,它们负责把所有的单例 Bean 提前创建好,确保系统在运行时可以直接使用这些对象。

12 finishRefresh

prepareRefresh()` 这个方法的主要作用是为容器的刷新做好准备。它会设置一些基础的状态,比如记录启动时间、标记容器是否激活,还会检查配置文件是否正确,备份事件监听器,并收集一些需要提前处理的事件。这些工作都为后面加载和初始化 Bean 做好了铺垫。

finishRefresh()是Spring容器刷新的最后阶段,主要完成:

  • 清除资源缓存;

  • 初始化生命周期处理器并触发onRefresh()启动Lifecycle组件;

  • 发布ContextRefreshedEvent事件通知刷新完成;

  • 注册JMX监控(非Native环境)。该阶段确保所有单例Bean初始化后,有序启动生命周期组件并通知监听器,标志容器完全就绪。


/**
 * 完成上下文的刷新过程,主要执行以下操作:
 * 1. 清理资源缓存
 * 2. 初始化生命周期处理器
 * 3. 触发生命周期处理器的刷新回调
 * 4. 发布上下文刷新完成事件
 * 5. 注册JMX管理Bean(非原生镜像环境)
 * 
 * 注意:此方法会在 refresh() 方法的 finally 块中被调用,确保无论初始化成功与否都会执行资源清理
 */
@SuppressWarnings("deprecation")  // 抑制已弃用方法的警告
protected void finishRefresh() {
    // 1. 清理上下文级别的资源缓存(如ASM扫描的元数据)
    // 这些缓存在启动阶段用于加速Bean定义解析,启动完成后可释放以节省内存
    clearResourceCaches();

    // 2. 初始化生命周期处理器
    // 如果容器中存在名为"lifecycleProcessor"的Bean则使用,否则创建默认的DefaultLifecycleProcessor
    initLifecycleProcessor();

    // 3. 首先将刷新事件传播给生命周期处理器
    // 这会触发所有实现了Lifecycle接口的Bean的start()方法
    // 典型应用:启动内嵌Web服务器、消息监听容器等
    getLifecycleProcessor().onRefresh();

    // 4. 发布最终的ContextRefreshedEvent事件
    // 通知所有监听器上下文已刷新完成,应用可在此事件中执行后置初始化逻辑
    // 事件发布是同步的,监听器会按注册顺序立即执行
    publishEvent(new ContextRefreshedEvent(this));

    // 5. 如果不在原生镜像中运行,则注册LiveBeansView MBean
    // 用于JMX监控当前活动的Bean及其依赖关系
    // 在Spring Native环境中会自动跳过此步骤
    if (!NativeDetector.inNativeImage()) {
        LiveBeansView.registerApplicationContext(this);
    }
}

finishRefresh() 是 Spring 容器刷新过程的最后一步,主要干这几件事:

  • 清理垃圾:把启动过程中用到的一些临时资源缓存清理掉,省下内存。
  • 启动“管家”:初始化一个叫生命周期处理器的东西 Lifecycle组件,它会负责管理一些需要在特定时间启动或停止的组件。
  • 通知大家容器准备好了:发布一个ContextRefreshedEvent 事件,告诉所有监听者,“容器已经刷新完成啦,可以开始干活了!”
  • 注册监控功能(如果环境支持的话):让 JMX 能够监控当前容器里活跃的 Bean 和它们的关系。不过如果是 Native 环境,这步会跳过。

简单来说,这个阶段就是确保所有的单例 Bean 都初始化完成后,再启动那些需要运行的组件,并通知监听器,表示整个容器已经完全准备好可以用了。

工厂模式 与 IOC容器的关系:

接下来, 开始介绍 工厂模式 与 IOC容器的关系。

由于 平台篇幅限制,这里 省了 10000 字…

原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址

  • 最直观的例子:汽车制造厂

  • 工厂模式的核心价值:

  • 工厂模式适用场景:

  • BeanFactory对简单工厂的实现

    1. BeanFactory的简单工厂模式结构
  • 2 核心源码分析

    • 2-1 BeanFactory接口
    • 2-2 DefaultListableBeanFactory实现
    • 2-3 创建Bean的核心方法
    1. 简单工厂模式的体现
    • 3-1 集中创建对象
    • 3-2 通过标识符获取对象
    • 3-3 隐藏创建细节
  • 工厂方法模式: FactoryBean对工厂方法模式的实现

    • 什么是 工厂方法模式 模式?

    • 工厂方法模式 特点:

    • Spring的是工厂方法模式: FactoryBean

      1. FactoryBean的核心设计
      1. 核心源码分析
      • 2-1 FactoryBean接口
      • 2-2 FactoryBean在BeanFactory中的处理
      • 2-3 FactoryBeanRegistrySupport
      1. 工厂方法模式的体现
      • 3-1 定义创建对象的接口
      • 3-2 由子类决定实例化过程
      • 3-3 延迟实例化
      1. Spring内置的FactoryBean实现示例
      • 4-1 ProxyFactoryBean (AOP代理创建)
      • 4-2 SqlSessionFactoryBean (MyBatis集成)
      1. 自定义FactoryBean示例
      1. 与传统工厂方法模式的区别
    • 抽象工厂模式 (Abstract Factory)

      • 抽象工厂模式 (Abstract Factory)特点:
    • ApplicationContext对抽象工厂模式实现

      • 1、抽象工厂模式的核心结构
      • 2、BeanFactory 接口定义
      • 3、ApplicationContext 的继承结构
      • 4、ApplicationContext 的具体工厂实现
      • 4-1). ClassPathXmlApplicationContext
      • 4-2). AnnotationConfigApplicationContext
      • 5、产品(Bean)的创建与管理
      • 5-1、 Bean 的创建流程
      • 5-2、 Bean 的获取逻辑
      • 6、抽象工厂模式在 获取 Bean 场景当中的 超级灵活性
        • 6-1、 客户端与工厂的解耦
        • 6-2、 多工厂实现的切换
        • 6-3、 产品创建的统一接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值