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. string 字符串转为 char *

    std::string str = "abc"; const char *p = str.data(); 更多: https://www.cnblogs.com/devilmayc ...

  2. git回退至指定版本,并更新远程仓库

    1. git log   查到commit记录 2.复制 commit 后面的id 3. git reset --hard  commit 后面的id   // 回退 4. 强制更新远程仓库  git ...

  3. 小程序threejs参考

    之前做了一个小程序眼镜试戴的功能,涉及了人脸识别和3D模型渲染等.暂时记录一些参考的东西,有时间再整理. threejs官方文档(一定要看看) https://threejs.org/docs/ind ...

  4. mongodb(2022)

    了解 文档数据库MongoDB用于记录文档结构的数据,如JSON.XML结构的数据.一条文档就是一条记录(含数据和数据结构),一条记录里可以包含若干个键值对.键值对由键和值两部分组成,键又叫做字段.键 ...

  5. Linux开端---Centos

    Linux-Centos 虚拟化所需工具:https://pan.baidu.com/s/1643-kYcx9oPGnGEZM1pLOw?pwd=g0v5 提取码:g0v5 问题解决 正常注册网络适配 ...

  6. Unity3D之OnTriggerEnter和OnCollisionEnter

    OnCollisionEnter方法要求碰撞的发起方必须拥有刚体,而被碰撞方有没有刚体并不重要; OnTriggerEnter方法则对此没有要求,只需要碰撞双方有一个具有刚体即可触发,当有物体勾选is ...

  7. 了解 Docker 网络

    本章将会简单地讲述 Docker 中的网络,对于 CNM.Libnetwork 这些,限于笔者个人水平,将不会包含在内. Docker 的四种网络模式 Docker 有 bridge.none.hos ...

  8. 浅入Kubernetes(4):使用Minikube体验

    Minikube 打开 https://github.com/kubernetes/minikube/releases/tag/v1.19.0 下载最新版本的二进制软件包(deb.rpm包),再使用 ...

  9. C#多线程(7):手动线程通知

    目录 区别与示例 ManualResetEvent 类 ManualResetEventSlim 区别与示例 AutoResetEvent 和 ManualResetEvent 十分相似.两者之间的区 ...

  10. springboot,简要记录,方便复习,

    boot 笔记第一步新建工程,导包,由于boot的数据库框架是用mybtis -paus,所以关于数据库系统那儿不用色选mybatis ,需要重新maven导包完整导包以下人容: <?xml v ...