mid - BeanDefinition + BeanFactory + IOC 核心容器 · SpringBoot3
BeanDefinition
- Bean配置蓝图
作用
Spring 在扫描类、解析 @Bean、解析 XML 的时候,
不会立刻创建对象Bean,而是先把这些信息解析成 BeanDefinition。
内容
- BeanName BeanClass 作用域
- 生命周期的配置: lazyInit 、 initMethodName、destroyMethodName
- 依赖注入: 构造器参数、属性注入、依赖
流程中的位置
扫描配置类 / 注解 / XML
→ 解析得到 BeanDefinition
→ 注册到 BeanFactory
→ 后续实例化 Bean
BeanFactoryPostProcessor
- 新增、修改BeanDefinition 及Bean的属性配置
- 处理 BeanDefinition 所在的 BeanFactory
- Bean工厂后置处理器,当BeanFactory准备好了后(Bean初始化之前),会调用该接口的 postProcessBeanFactory法,经常用于新增BeanDefinition
| 实现类名 | 作用 |
|---|---|
| ConfigurationClassPostProcessor | 扫描启动类所在包下的注解 |
| ServletComponentRegisteringPostProcessor | 扫描 @WebServlet、@WebFilter、@WebListener |
| CachingMetadataReaderFactoryPostProcessor | 配置 ConfigurationClassPostProcessor |
| ConfigurationWarningsPostProcessor | 配置警告提示 |
BeanFactory
1.what
BeanFactory 是 Spring IOC 容器的根接口,负责:
- 保存
BeanDefinition - 创建 Bean
- 获取 Bean
- 管理 Bean 的依赖关系和作用域
2. 它和 BeanDefinition 的关系
这个必须连起来讲。
BeanDefinition= Bean 的配置蓝图BeanFactory= 根据蓝图创建和管理 Bean 的工厂
也就是说:
BeanFactory 不是凭空造 Bean,
而是先拿到 BeanDefinition,再决定怎么实例化 Bean。
这句是核心:
BeanDefinition 负责描述,BeanFactory 负责落地创建。
3. 它在流程中的位置
这个你也得会。
逻辑链直接记:
扫描得到 BeanDefinition
→ 注册到 BeanFactory
→ BeanFactory 在后续实例化 Bean
→ 把 Bean 放进单例池或返回给调用方
BeanDefinition 通常会先注册到 BeanFactory 内部的 BeanDefinitionMap 中,后续再据此创建 Bean。
也就是说,BeanFactory 是连接
定义信息 和 真实对象 的中间执行者。
4. 它最常用的能力有哪些
你现在写了 containsBean、getBean、isPrototype/isSingleton,但还不够完整。
你最少得知道这些能力:
获取 Bean
getBean()
判断是否存在
containsBean(String name)
判断作用域
isSingleton(String name)isPrototype(String name)
获取类型
getType(String name)
获取别名
getAliases(String name)
这里不用全背方法签名,但要知道它大概能干啥。
5. 常见实现类要知道谁最重要
必须知道:
DefaultListableBeanFactory
它是 Spring 中最核心、最常见的 BeanFactory 实现之一。
为什么叫这个名字?
Default:默认常用实现Listable:支持按列表方式获取 Bean、枚举 BeanDefinitionBeanFactory:Bean 工厂本体
它的重要性在于:
很多
ApplicationContext底层真正持有的,就是它
所以你可以写一句:
IOC 容器底层实际管理 Bean 时,核心往往依赖的是 DefaultListableBeanFactory。
6. BeanFactory 和 ApplicationContext 的区别
BeanFactory 是最基础的容器,提供最核心的 Bean 管理能力。
ApplicationContext 是它的增强版,除了 Bean 管理,还提供:
- 国际化
- 事件机制
- 资源加载
- 自动注册后置处理器
- 更完整的企业级能力
一句话:
BeanFactory偏底层,ApplicationContext偏完整。
7. 默认是否懒加载
BeanFactory 这种最基础容器,偏向 按需获取 Bean。
而 ApplicationContext 通常在容器启动时,就会提前实例化非懒加载单例 Bean。
IOC容器
初始化流程
1. 准备BeanFactory
主要做两件事: ClassLoader 、 Environment
- 设置 ClassLoader —> 告诉Spring去哪里加载类
- 反射创建 Bean
- 扫描类
- 解析注解
- 设置 Environment —> 拿到配置
- 比如yaml文件中的 server: port: 8080 这些信息就是从Envir来
- 包含
application.yml, 环境变量, JVM参数, 命令行参数等
2. 执行 BeanFactoryPostProcessor
解析并注册 BeanDefinition
- 执行Bean工厂的
后置处理器 BeanFactoryPostProcessor- ConfigurationClassPostProcessor
- 解析配置类、@ComponentScan、@Bean、@Import
- 扫描并注册 BeanDefinition
- 扫描指的是: 执行BeanFactory后置处理器, 得到并注册BeanDefinition, 而不是直接创建Bean实例
- ConfigurationClassPostProcessor
3. 注册BeanPostProcessor
注册用于处理 Bean 实例的处理器, 注意只是注册
- 在 BeanDefinition 注册完成后,Spring 会注册 BeanPostProcessor
- 它不会在这一阶段直接处理普通 Bean
- 它的作用是:后续 Bean 实例化时, 在初始化前后对 Bean 进行增强处理
- 常见用途:
- AOP 代理对象创建
- @Autowired 依赖注入处理
- 初始化前后扩展逻辑
代码块收起展开
refresh()
→ 注册 BeanPostProcessor (只是放进去)
→ 实例化 Bean
↓
createBean()
↓
applyBeanPostProcessorBeforeInitialization()
↓
初始化方法
↓
applyBeanPostProcessorAfterInitialization()4. 实例化非懒加载单例 Bean
将单例 BeanDefinition 批量变成真正的 Bean 对象
- 在 BeanFactory、BeanDefinition 和 BeanPostProcessor 都准备完成后,Spring 会开始实例化容器中的非懒加载单例 Bean
- 默认情况下,单例 Bean 会在容器启动阶段完成创建
- 多例 Bean 和懒加载 Bean 不会在此时实例化,而是在真正使用时再创建
这一阶段大致会完成这些事情
- 根据 BeanDefinition 创建对象
- 完成属性注入
- 执行 Aware 接口回调
- 执行 BeanPostProcessor 前置处理
- 执行初始化方法
- 执行 BeanPostProcessor 后置处理
- 最后把创建好的单例 Bean 放入单例池中
为什么只实例化非懒加载单例 Bean
- 单例 Bean 是容器级共享对象,通常需要在应用启动时提前准备好
- 如果是懒加载 Bean,Spring 会等真正使用时再创建
- 如果是多例 Bean,每次获取都可能创建新对象,因此不会在容器启动阶段统一实例化
这一阶段是 IOC 容器真正把“Bean 定义”变成“Bean 对象”的核心步骤
5. 初始化事件多播器 & 绑定事件监听器
前者 -> 准备事件的广播中心 ---> 发信息
- Spring初始化
ApplicationEventMulticaster - 统一接收和分发容器的事件
后者 -> 建立事件与监听器的关系 ---> 收信息
- 将容器中的 ApplicationListener 注册到事件多播器中
- 监听器可以来自:
- Spring 默认
- 自定义实现
- 自动装配
- 绑定完成后,事件就可以被监听器接收
发布事件
- Spring 在容器不同阶段发布事件 (启动完成/失败)
- 事件会交给事件多播器
- 多播器广播给匹配的监听器
- 监听器执行
onApplicationEvent()完成拓展逻辑
事件机制核心链路:
Spring 发布事件 → 多播器分发 → 监听器处理
Spring IOC 容器初始化主要发生在 refresh() 方法中。 1. 首先会准备 BeanFactory,并设置类加载器和环境信息。 2. 然后执行 BeanFactoryPostProcessor,在这个阶段完成 BeanDefinition 的解析和注册。 3. 接着注册 BeanPostProcessor,这些处理器会在后续 Bean 创建过程中参与增强。 4. 之后实例化非懒加载的单例 Bean,完成依赖注入和初始化,并放入单例池。 5. 最后初始化事件多播器,注册监听器,并在不同阶段发布事件,由监听器完成扩展逻辑。
Bean的生命周期
创建对象
实例化
根据BeanDefition找类, 调出构造方法来new对象, 注意这里只是分配地址罢了
依赖注入
给new出来的对象填充属性
- @Autowired
- @Value 三级缓存补充
初始化
Aware回调
把容器的一些信息告诉该 Bean
- BeanName
- ApplicationContext
执行初始化方法
- @PostConstruct
- init-method
初始化后增强
执行BeanPostProcessor的after方法
AOP 是在 Bean 初始化完成后,通过 BeanPostProcessor 的 after 方法生成代理对象,并用代理对象替换原始 Bean,从而实现方法增强。
最后将Bean放入单例池
使用后销毁
- 执行DisposableBean(先执行@PreDestory)
总结
总:IOC 容器的初始化,核心工作是在 AbstractApplicationContext.refresh() 方法中完成的
分:在 refresh 方法中主要做了这么几件事:
- 准备 BeanFactory,在这一块需要给 BeanFactory 设置很多属性,比如类加载器、Environment 等
- 执行 BeanFactoryPostProcessor,这一阶段会扫描要放入到容器中的 Bean 信息,得到对应的 BeanDefinition(注意,这里只扫描,不创建)
- 注册 BeanPostProcessor,我们自定义的 BeanPostProcessor 就是在这个阶段被加载的,将来 Bean 对象实例化好后需要用到
- 实例化容器中非懒加载的单例 Bean,多例 Bean 和懒加载的 Bean 不会在这个阶段实例化,将来用到的时候再创建
- 当容器初始化完毕后,再做一些扫尾工作,比如清除缓存等
总:简单总结一下,在 IOC 容器初始化的过程中,首先得准备并执行 BeanFactory 后置处理器,其次得注册 Bean 后置处理器,并启动 tomcat,最后需要借助于 BeanFactory 完成 Bean 的实例化
调用链层:
finishBeanFactoryInitialization → preInstantiateSingletons → 循环 getBean → doGetBean → getSingleton(先查缓存,miss 了就调 lambda 去 createBean)→ doCreateBean。整条链跨了好几个类,面试答出类名加分。
doCreateBean 三步(最核心):
createBeanInstance— 反射调构造器,得到一个”空壳” BeanpopulateBean— 依赖注入,把@Autowired的字段填进去initializeBean— 初始化,里面又是四个有序的子步骤
initializeBean 四步顺序必须记住,面试高频考:
invokeAwareMethods → BPP.before →
invokeInitMethods(@PostConstruct 先于 afterPropertiesSet)→ BPP.after(AOP 代理就是在这里生成的)