Spring Bean 的一生
Spring Bean 的一生包括其从创建到消亡的整个过程:
实例创建 => 填充 => 初始化 => 使用 => 销毁。
这里需要注意的是,从 bean 实例的创建到可以使用之间还包括【填充】和【初始化】两个步骤。
AbstractAutowireCapableBeanFactory::createBean:bean 创建核心方法,包含创建、填充 bean 实例及应用 post-processors 等逻辑。
一、实例创建
1、实例化前置处理
InstantiationAwareBeanPostProcessor 为 BeanPostProcessor 子接口,用以提供【创建实例】前后回调处理。
如果有实现 InstantiationAwareBeanPostProcessor 接口,则应用此接口,返回结果如果不为 null,则直接返回作为 bean 实例。
2、doCreateBean
实际用于执行 bean 创建的方法,所有的创建、填充、初始化、注册销毁等逻辑都在此处处理。
BeanWrapper:Spring 底层 JavaBean 结构核心接口,提供了分析和管理 JavaBean 的相关操作。不直接使用,通常隐式的通过 BeanFactory 或者 DataBinder 来使用。此处执行逻辑即为使用 BeanWrapper 对象。
factoryBeanInstanceCache:存储 FactoryBean name --> BeanWrapper 键值映射。执行实例创建伊始,会先从 factoryBeanInstanceCache 查询获取,存在则直接获取(获取后删除)使用。
好吧,这里有个问题,为什么会有个 factoryBeanInstanceCache 缓存?
源头在于对单例 FactoryBean 类型操作,getSingletonFactoryBeanForTypeCheck。
创建 bean 实例 createBeanInstance:
优先级顺序:
通过 InstanceSupplier 创建(5.0以后)
通过工厂方法创建
构造函数创建
至此,bean 实例已创建完毕。
此处还有一个 post-processor 处理:MergedBeanDefinitionPostProcessor,用于 bean 定义修改(只针对 RootBeanDefinition:merge 了多个来源 BeanDefinition 的运行时视图)。
3、单例实例提前暴露
为了解决单例循环依赖问题,提前将未完全创建好的单例实例缓存起来。
这里说的未完全创建好是指还不能正常使用。
earlySingletonExposure 条件:
单例:scope 为 “singleton” 或者 ”“。
允许自动处理循环依赖:allowCircularReferences 默认 true
单例 bean 处于创建中:DefaultSingletonBeanRegistry:singletonsCurrentlyInCreation 存储所有处于创建中的 bean 名称。
addSingletonFactory:
将 singletonFactory 添加到 singletonFactories 缓存中,以备解决循环依赖使用。
singletonFactories 是什么呢?
字面意思为单例工厂缓存(bean name -> ObjectFactory ):即所谓的第三级缓存,存储目标 bean 所对应的 bean 工厂对象键值。
那 ObjectFactory 这个对象是怎么获取的呢?
SmartInstantiationAwareBeanPostProcessor::getEarlyBeanReference
SmartInstantiationAwareBeanPostProcessor 是 InstantiationAwareBeanPostProcessor 的扩展接口。
InstantiationAwareBeanPostProcessor 我们说过,是作用在创建实例前后。此处为创建实例后情景。
ObjectFactory 虽名为工厂,其实际为用以在 bean 创建早期,访问相应 bean 的一个引用。
什么是早期呢?
就是这会儿,刚创建完实例,还没有进行相应的填充、初始化等后续操作。
那为什么是暴露个引用,而不是直接给出目标对象呢?
因为目标 bean 可能还会经过其它 post-processors 处理。像 AbstractAutoProxyCreator::getEarlyBeanReference 中的代理逻辑处理。
二、填充
属性填充,作用于 AbstractAutowireCapableBeanFactory::populateBean。
1、属性填充前置处理
continueWithPropertyPopulation:是否继续处理属性填充判断。
这里的说明是在执行属性填充前给予任何 InstantiationAwareBeanPostProcessors 一个机会来变更 bean 的状态。
什么意思呢?
就是 InstantiationAwareBeanPostProcessors 的 postProcessAfterInstantiation 处理,对目标 bean 做相应的变更。
做什么变更呢?
这个节点在 Spring 自动注入操作之前,可以执行个性化的属性注入。同时,方法返回值会赋予 continueWithPropertyPopulation,以决定是否执行后续的逻辑。
这里有一个点需要注意:
如果当前 InstantiationAwareBeanPostProcessors::postProcessAfterInstantiation 返回 false,那么 bean 属性填充步骤则就此终止,不会再执行其它的 InstantiationAwareBeanPostProcessors 及后续的 Spring bean 属性填充过程。
2、属性填充
MutablePropertyValues
PropertyValues 接口的一个实现,提供对属性的各种操作,同时提供相应的构造函数来支持深度复制及基于 Map 的构造。
自动注入方式:按顺序 BY_NAME => BY_TYPE
BY_NAME
autowireByName 根据名称填充
填充什么呢?
unsatisfiedNonSimpleProperties。
什么是 unsatisfiedNonSimpleProperties 呢?
可写的:即拥有写方法。
需要依赖检查的:基于 ignoredDependencyTypes 属性设置判断。
非本身类型的。
非简单类型属性的:属性本身类型及数组元素类型为非简单类型。包括(基本类型及其包装类型,如 int、Integer 等)
注入:
首先根据属性名称判断 bean 存在:
即是否包含在 bean 工厂及外部注册单例 bean。
alias 的,会做相应的名称转换。
存在继承关系的,会级联向上查询。
根据属性名称获取 bean:AbstractBeanFactory::getBean。
属性设置。
注册 bean 依赖:dependentBeanMap beanName -> Set<BeanName>,即记录 bean 及其依赖 bean 关系。
BY_TYPE
autowireByName 根据类型填充。
一个 BeanFactory 里必须恰好只有一个匹配需要类型。
同样,首先获取需要填充的属性:unsatisfiedNonSimpleProperties。
排除 Object 类型属性,填充没有意义。
处理依赖。
属性设置
注册 bean 依赖。
3、依赖检查
依赖检查分为两部分:一个基于 InstantiationAwareBeanPostProcessor::postProcessPropertyValues 处理。一个基于 AbstractBeanDefinition::dependencyCheck 处理。
InstantiationAwareBeanPostProcessor:
对特定的属性进行依赖检查及处理;对特定属性值进行替换,添加或者删除。
如 RequiredAnnotationBeanPostProcessor、 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、MockitoPostProcessor等。
dependencyCheck
检查所有暴露的属性是否都已赋值。
4、属性赋值
将上述处理过的属性值填充到 bean 实例。
三、初始化
应用工厂回调,定义的初始化方法及post-processors。
1、Aware 处理
Aware 代表了各种各样的资源,处理 Aware 即为将相应的资源添加到 bean 实例中。
如 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 等。
2、BeanPostProcessorsBeforeInitialization
顾名思义,这里的 BeanPostProcessors 是初始化之前的处理。
如 AbstractAdvisingBeanPostProcessor 检查。
3、执行初始化方法
a)实现了 InitializingBean 接口的 bean,执行相应的 afterPropertiesSet 方法。
b)定义了 initMethod 的,触发相应的方法调用。
两者是否可以同时存在呢?
可以,如果同时存在,但是初始化方法名称不能为 afterPropertiesSet。执行顺序为先 a 后 b。
4、BeanPostProcessorsAfterInitialization
同 2,此处为初始化之后的处理。
如 BeanValidationPostProcessor、ApplicationListenerDetector 等。
其实很多 PostProcessor 是既有 Before 处理逻辑,亦有 After 处理逻辑的,此处不再赘述。
四、disposable bean 注册
bean 工厂维护了一个 disposable bean 列表(bean name --> disposable instance)。在工厂关闭销毁时,同时销毁相应的 bean 实例对象。
定义销毁可以通过实现 DisposableBean 或者 AutoCloseable 接口或者自定义销毁方法。
如果使用一个定义了相应销毁方法的对象,又不想其执行销毁方法时怎么办呢?
注解或者配置其销毁方法为空,如:@Bean(destroyMethod = "")。
DestructionAwareBeanPostProcessor:实例销毁前,用户可以自定义执行特定的操作。如:ApplicationListenerDetector 移除相应的 Listener;ScheduledAnnotationBeanPostProcessor 移除定时任务等。
Spring Bean 的一生的更多相关文章
- Spring Bean的一生
Spring Bean的一生 When you work directly in Java, you can do anything you like with your objects and do ...
- Spring 了解Bean的一生(生命周期)
转载 https://blog.csdn.net/w_linux/article/details/80086950 该篇博客就来了解IoC容器下Bean的一生吧,也可以理解为bean的生命周期. ## ...
- Spring Bean生命周期,好像人的一生。。
大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...
- Spring8:一些常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
- Spring Bean详细讲解
什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象. Spring 容器会自动完成@bean对象的实例化. 创建应用对象之间的协作关系的行为称为:装配( ...
- Spring Bean的生命周期(非常详细)
Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...
- spring bean的生命周期
掌握好spring bean的生命周期,对spring的扩展大有帮助. spring bean的生命周期(推荐看) spring bean的生命周期
- spring bean的重新加载
架构体系 在谈spring bean的重新加载前,首先我们来看看spring ioc容器. spring ioc容器主要功能是完成对bean的创建.依赖注入和管理等功能,而这些功能的实现是有下面几个组 ...
- Spring Bean
一.Spring的几大模块:Data access & Integration.Transcation.Instrumentation.Core Spring Container.Testin ...
- 【转】Spring bean处理——回调函数
Spring bean处理——回调函数 Spring中定义了三个可以用来对Spring bean或生成bean的BeanFactory进行处理的接口,InitializingBean.BeanPost ...
随机推荐
- win32 - SetWinEventHook的用法
#include <Windows.h> #include <iostream> #include <thread> #include <tchar.h> ...
- Apple设备屏幕尺寸和方向
表格中包括了各种型号的iPad.iPhone.以及iPod touch等设备的详细信息,涵盖了从iPad Pro到各代iPhone和iPod touch的多个型号. 这些信息可用于开发应用程序时优化界 ...
- itsdangerous模块的使用
简介 生成临时身份令牌(通过邮件让用户注册激活的时候地址当中带有用户的信息.但是信息一般都是敏感信息,而且还想让它具有时效性,所以就可以选择itsdangerous模块 官网:https://itsd ...
- Sharding-JDBC源码解析与vivo的定制开发
作者:vivo IT 平台团队 - Xiong Huanxin Sharding-JDBC是在JDBC层提供服务的数据库中间件,在分库分表场景具有广泛应用.本文对Sharding-JDBC的解析.路由 ...
- 面试官问我会ES么,我说不会,抓紧学起【ES(一)聚合分析篇】
ES聚合分析 1.metric(指标)聚合 1.1 单值分析 min 求指定字段的最小值 # 求价格的最小值 { "size":0, "aggs":{ &quo ...
- vuecli-vite-vue3-init 项目架子 快速开发 webpack打包
要vite的开发的快速 和 webpack打包 开发的时候 用vite,可以打包一个本地可以直接双击,不用起服务的代码 这个架子的缺点就是 vite和vuecli 两套双配置 正式公司项目 还是vue ...
- vscode vue 鼠标Ctrl+单击 函数跳转 插件名称:vue-helper
- Nginx的负载均衡策略(4+2)
Nginx的负载均衡策略主要包括以下几种: 轮询(Round Robin):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除.这是Nginx的默认策略,适合服务器配置 ...
- 一个简易的ORM框架的实现(二)
框架目标 什么是框架,框架能做到什么? 把一个方向的技术研发做封装,具备通用性,让使用框架的开发者用起来很轻松. 属性: 通用性 健壮性 稳定性 扩展性 高性能 组件化 跨平台 从零开始-搭建框架 建 ...
- day28--Java泛型01
Java泛型01 1.泛型的理解和好处 看一个需求: 请编写程序,在ArrayList中添加三个Dog对象 Dog对象含有name和age,并输出name和age(要求使用getXXX()) 先用传统 ...