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 的一生的更多相关文章

  1. Spring Bean的一生

    Spring Bean的一生 When you work directly in Java, you can do anything you like with your objects and do ...

  2. Spring 了解Bean的一生(生命周期)

    转载 https://blog.csdn.net/w_linux/article/details/80086950 该篇博客就来了解IoC容器下Bean的一生吧,也可以理解为bean的生命周期. ## ...

  3. Spring Bean生命周期,好像人的一生。。

    大家好,我是老三,上节我们手撸了一个简单的IOC容器五分钟,手撸一个Spring容器!,这节我们来看一看Spring中Bean的生命周期,我发现,和人的一生真的很像. 简单说说IoC和Bean IoC ...

  4. Spring8:一些常用的Spring Bean扩展接口

    前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...

  5. Spring Bean详细讲解

    什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象. Spring 容器会自动完成@bean对象的实例化. 创建应用对象之间的协作关系的行为称为:装配( ...

  6. Spring Bean的生命周期(非常详细)

    Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ...

  7. spring bean的生命周期

    掌握好spring bean的生命周期,对spring的扩展大有帮助.  spring bean的生命周期(推荐看)  spring bean的生命周期

  8. spring bean的重新加载

    架构体系 在谈spring bean的重新加载前,首先我们来看看spring ioc容器. spring ioc容器主要功能是完成对bean的创建.依赖注入和管理等功能,而这些功能的实现是有下面几个组 ...

  9. Spring Bean

    一.Spring的几大模块:Data access & Integration.Transcation.Instrumentation.Core Spring Container.Testin ...

  10. 【转】Spring bean处理——回调函数

    Spring bean处理——回调函数 Spring中定义了三个可以用来对Spring bean或生成bean的BeanFactory进行处理的接口,InitializingBean.BeanPost ...

随机推荐

  1. 使用GDI时如何确定是否有内存泄漏

    在创建GDI对象时,比如创建笔,画刷等对象时,在调用完之后忘记删除对象了,会造成内存泄漏 我们可以通过任务管理器来快速的查看 启动任务管理器(右键单击Windows任务栏以选择任务管理器) 在Wind ...

  2. C/C++、C#、JAVA(三):字符串操作

    C/C++.C#.JAVA(三):字符串操作 目录 C/C++.C#.JAVA(三):字符串操作 定义字符串 C C++ C# JAVA 捕捉输入和输出 等值比较 C/C++ C# JAVA 字符串操 ...

  3. FolkMQ 是怎样进行消息的事务处理?

    FolkMQ 提供了二段式提交的事务提交的机制(TCC 模型).允许生产者在发送消息时绑定到一个事务中并接收事务的管理,以确保消息的原子性(要么全成功,要么全失败).在 FolkMQ 中,事务是通过 ...

  4. CXPACKET等待类型分析

    背景 客户反馈今天8点钟开始进入业务高峰期后,数据库的CPU利用率非常高,基本达到了100%,前端应用也非常慢.怀疑是昨晚业务系统升级导致,请我们紧急协助分析. 现象 登录到SQL专家云,进入相关时间 ...

  5. 小工具 --- 百度翻译API翻译工具

    引言 最近想把一些英文官方文档的资料翻译成中文,然后转化为Markdown文档,然后发现百度通用翻译的API有不错的免费额度,个人申请也能申请到高级版.这个额度足够个人的日常使用了. 如何使用 如何使 ...

  6. python中数字和字符串和bytes的相互转换实例解析

    一 数字和字符串的相互转换 # int convert string str(12345)) #string convert int int('12345') 二 数字和bytes的相互转换 1.数字 ...

  7. 26_H.264编码实战

    目录 使用FFmpeg命令进行H.264编码 使用FFmpeg代码实现H.264编码 1.获取编码器 2.创建上下文 3.打开编码器 4.创建 AVFrame 5.创建 AVPacket 6.打开文件 ...

  8. HISI3520DV300 折腾记录(一)之 《Uboot-Start.S分析 以及 相关启动流程分析》

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  9. Linux Char-Driver (字符驱动 摘要)(一)

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  10. Performance Improvements in .NET 8 -- Native AOT & VM & GC & Mono【翻译】

    原生 AOT 原生 AOT 在 .NET 7 中发布.它使 .NET 程序在构建时被编译成一个完全由原生代码组成的自包含可执行文件或库:在执行时不需要 JIT 来编译任何东西,实际上,编译的程序中没有 ...