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 ...
随机推荐
- 关于char * 和 char [] 的一点理解
截取一段有用的信息: c++的char[]和char*的区别 char str1[] = "abc": 这里的"abc"是一个常量,首先会在常量存储区里存储&q ...
- select_for_update悲观锁
例子,银行存款和撤销方法 1.用户A提取帐户 - 余额为100 $. 2.用户B提取帐户 - 余额为100 $. 3.用户B退出30 $ - 余额更新为100 $ - 30 $ = 70 $. 4.用 ...
- 第一百一十三篇: JS数组Array(二)数组方法 栈、队列、排序
好家伙, 在上一篇中,我们知道了, JS的数组中每个槽位可以存储任意类型的数据 那么,我们能通过数组去模仿某些数据结构吗? 答案是肯定的 1.栈方法 ECMAScript 给数组提供几个方法,让 ...
- 【Azure APIM】APIM 策略语句如何读取请求头中所携带的Cookie信息并保存为变量
问题描述 需要在APIM策略中对请求所携带的Cookie中的token值进行JWT验证,如果获取Cookie中的值并且作为变量保存,然后在JWT 验证中使用呢? 问题解答 第一步:获取Cookie中的 ...
- 云原生 on nLive:云上 Nebula Graph
本文首发于 Nebula Graph Community 公众号 在 #云原生# 主题分享中,来自 Nebula 云组的 Cloud 专家乔雷同大家分享云的相关知识,本文整理自该次主题直播. 云原生是 ...
- C/C++ 的 指针/引用 传参
#include <stdio.h> //指针传值 void addOne(int *a) { printf("%8p\n",a); *a = *a+1; } //引用 ...
- HttpRunner使用教程?
什么是HttpRunner? 它是一种面向http协议的测试框架,它只需要去维护一份yaml/json文件就可以使用自动化测试,结合locus性能测试,线上性能监控,持续集成等多种需求 工作原理: 通 ...
- Java 演示线程的死锁问题
1 package bytezero.deadlock; 2 3 /** 4 * 演示线程的死锁问题: 5 * 6 * 1.死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃 7 ...
- Metasploitable3 渗透测试
1.信息手机阶段 信息收集经常使用的软件 功能也比较强大的Nmap Nmap nmap -p- -sS -sV -n -v --reason --open -oX demon.xml 192.168. ...
- 【规范】看看人家Git提交描述,那叫一个规矩
前言 缘由 没想到玩了多年git,竟然还有提交描述规范 事情起因: 在工作迭代过程中,偶然发现同组小帅哥Git提交描述总是和自己的不大一样,秉承好奇至上的我特意去研究了下.竟然发现提交了这么多年的Gi ...