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. win32 - SetWinEventHook的用法

    #include <Windows.h> #include <iostream> #include <thread> #include <tchar.h> ...

  2. Apple设备屏幕尺寸和方向

    表格中包括了各种型号的iPad.iPhone.以及iPod touch等设备的详细信息,涵盖了从iPad Pro到各代iPhone和iPod touch的多个型号. 这些信息可用于开发应用程序时优化界 ...

  3. itsdangerous模块的使用

    简介 生成临时身份令牌(通过邮件让用户注册激活的时候地址当中带有用户的信息.但是信息一般都是敏感信息,而且还想让它具有时效性,所以就可以选择itsdangerous模块 官网:https://itsd ...

  4. Sharding-JDBC源码解析与vivo的定制开发

    作者:vivo IT 平台团队 - Xiong Huanxin Sharding-JDBC是在JDBC层提供服务的数据库中间件,在分库分表场景具有广泛应用.本文对Sharding-JDBC的解析.路由 ...

  5. 面试官问我会ES么,我说不会,抓紧学起【ES(一)聚合分析篇】

    ES聚合分析 1.metric(指标)聚合 1.1 单值分析 min 求指定字段的最小值 # 求价格的最小值 { "size":0, "aggs":{ &quo ...

  6. vuecli-vite-vue3-init 项目架子 快速开发 webpack打包

    要vite的开发的快速 和 webpack打包 开发的时候 用vite,可以打包一个本地可以直接双击,不用起服务的代码 这个架子的缺点就是 vite和vuecli 两套双配置 正式公司项目 还是vue ...

  7. vscode vue 鼠标Ctrl+单击 函数跳转 插件名称:vue-helper

  8. Nginx的负载均衡策略(4+2)

    Nginx的负载均衡策略主要包括以下几种: 轮询(Round Robin):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除.这是Nginx的默认策略,适合服务器配置 ...

  9. 一个简易的ORM框架的实现(二)

    框架目标 什么是框架,框架能做到什么? 把一个方向的技术研发做封装,具备通用性,让使用框架的开发者用起来很轻松. 属性: 通用性 健壮性 稳定性 扩展性 高性能 组件化 跨平台 从零开始-搭建框架 建 ...

  10. day28--Java泛型01

    Java泛型01 1.泛型的理解和好处 看一个需求: 请编写程序,在ArrayList中添加三个Dog对象 Dog对象含有name和age,并输出name和age(要求使用getXXX()) 先用传统 ...