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 ...
随机推荐
- string 字符串转为 char *
std::string str = "abc"; const char *p = str.data(); 更多: https://www.cnblogs.com/devilmayc ...
- git回退至指定版本,并更新远程仓库
1. git log 查到commit记录 2.复制 commit 后面的id 3. git reset --hard commit 后面的id // 回退 4. 强制更新远程仓库 git ...
- 小程序threejs参考
之前做了一个小程序眼镜试戴的功能,涉及了人脸识别和3D模型渲染等.暂时记录一些参考的东西,有时间再整理. threejs官方文档(一定要看看) https://threejs.org/docs/ind ...
- mongodb(2022)
了解 文档数据库MongoDB用于记录文档结构的数据,如JSON.XML结构的数据.一条文档就是一条记录(含数据和数据结构),一条记录里可以包含若干个键值对.键值对由键和值两部分组成,键又叫做字段.键 ...
- Linux开端---Centos
Linux-Centos 虚拟化所需工具:https://pan.baidu.com/s/1643-kYcx9oPGnGEZM1pLOw?pwd=g0v5 提取码:g0v5 问题解决 正常注册网络适配 ...
- Unity3D之OnTriggerEnter和OnCollisionEnter
OnCollisionEnter方法要求碰撞的发起方必须拥有刚体,而被碰撞方有没有刚体并不重要; OnTriggerEnter方法则对此没有要求,只需要碰撞双方有一个具有刚体即可触发,当有物体勾选is ...
- 了解 Docker 网络
本章将会简单地讲述 Docker 中的网络,对于 CNM.Libnetwork 这些,限于笔者个人水平,将不会包含在内. Docker 的四种网络模式 Docker 有 bridge.none.hos ...
- 浅入Kubernetes(4):使用Minikube体验
Minikube 打开 https://github.com/kubernetes/minikube/releases/tag/v1.19.0 下载最新版本的二进制软件包(deb.rpm包),再使用 ...
- C#多线程(7):手动线程通知
目录 区别与示例 ManualResetEvent 类 ManualResetEventSlim 区别与示例 AutoResetEvent 和 ManualResetEvent 十分相似.两者之间的区 ...
- springboot,简要记录,方便复习,
boot 笔记第一步新建工程,导包,由于boot的数据库框架是用mybtis -paus,所以关于数据库系统那儿不用色选mybatis ,需要重新maven导包完整导包以下人容: <?xml v ...