文章目录

  • 前言
  • 生命周期
  • 详细描述
    • 处理名称,检查缓存
    • 处理父子容器
    • 处理 dependsOn
    • 选择 scope 策略
    • 创建 bean - 创建 bean 实例
    • 创建 bean - 依赖注入
    • 创建 bean - 初始化
    • 创建 bean - 注册可销毁 bean
    • 类型转换处理
    • 销毁 bean

前言

对于一个长期的spring使用者来说,对于spring 的生命周期不是很了解,所以趁着这个疫情比较严重的时候,在家静下心来,看一下这个很久困在心中的一个问题。

生命周期

它大致分为Bean 定义Bean 的初始化Bean 的生存期Bean的销毁4 个部分。其中Bean 定义过程大致如下:

  • Spring 通过我们的配置,如@ComponentScan定义的扫描路径去找到带有@Component 的类,这个过程就是一个资源定位的过程。
  • 一旦找到了资源,那么它就开始解析,并且将定义的信息保存起来。注意,此时还没有初始化Bean,也就没有Bean 的实例,它有的仅仅是Bean 的定义。
  • 然后就会把Bean 定义发布到Spring IoC 容器中。此时, IoC 容器也只有Bean的定义,还是没有Bean的实例生成。

完成了这3 步只是一个资源定位并将Bean的定义发布到IoC容器的过程,还没有Bean实例的生成,更没有完成依赖注入。在默认的情况下, Spring 会继续去完成Bean的实例化和依赖注入,这样从IoC容器中就可以得到一个依赖注入完成的Bean 。但是,有些Bean 会受到变化因素的影响,这
时我们倒希望是取出Bean 的时候完成初始化和依赖注入,换句话说就是让那些Bean 只是将定义发布到IoC 容器而不做实例化和依赖注入, 当我们取出来的时候才做初始化和依赖注入等操作。

ComponentScan 中还有一个配置项lazyI init,只可以配置Boolean值,且默认值为false ,也就是默认不进行延迟初始化,因此在默认的情况下Spring会对Bean进行实例化和依赖注入对应的属性值。

详细描述

bean 的生命周期从调用 beanFactory 的 getBean 开始,到这个 bean 被销毁,可以总结为以下七个阶段:

  1. 处理名称,检查缓存
  2. 处理父子容器
  3. 处理 dependsOn
  4. 选择 scope 策略
  5. 创建 bean
  6. 类型转换处理
  7. 销毁 bean

处理名称,检查缓存

  • 这一步会处理别名,将别名解析为实际名称
  • 对 FactoryBean 也会特殊处理,如果以 & 开头表示要获取 FactoryBean 本身,否则表示要获取其产品
  • 这里针对单例对象会检查一级、二级、三级缓存
    • singletonFactories 三级缓存,存放单例工厂对象
    • earlySingletonObjects 二级缓存,存放单例工厂的产品对象
      • 如果发生循环依赖,产品是代理;无循环依赖,产品是原始对象
    • singletonObjects 一级缓存,存放单例成品对象

处理父子容器

  • 如果当前容器根据名字找不到这个 bean,此时若父容器存在,则执行父容器的 getBean 流程
  • 父子容器的 bean 名称可以重复

处理 dependsOn

  • 如果当前 bean 有通过 dependsOn 指定了非显式依赖的 bean,这一步会提前创建这些 dependsOn 的 bean
  • 所谓非显式依赖,就是指两个 bean 之间不存在直接依赖关系,但需要控制它们的创建先后顺序

选择 scope 策略

  • 对于 singleton scope,首先到单例池去获取 bean,如果有则直接返回,没有再进入创建流程
  • 对于 prototype scope,每次都会进入创建流程
  • 对于自定义 scope,例如 request,首先到 request 域获取 bean,如果有则直接返回,没有再进入创建流程

创建 bean - 创建 bean 实例

要点 总结
有自定义 TargetSource 的情况 由 AnnotationAwareAspectJAutoProxyCreator 创建代理返回
Supplier 方式创建 bean 实例 为 Spring 5.0 新增功能,方便编程方式创建 bean 实例
FactoryMethod 方式 创建 bean 实例 ① 分成静态工厂与实例工厂;② 工厂方法若有参数,需要对工厂方法参数进行解析,利用 resolveDependency;③ 如果有多个工厂方法候选者,还要进一步按权重筛选
AutowiredAnnotationBeanPostProcessor ① 优先选择带 @Autowired 注解的构造;② 若有唯一的带参构造,也会入选
mbd.getPreferredConstructors 选择所有公共构造,这些构造之间按权重筛选
采用默认构造 如果上面的后处理器和 BeanDefiniation 都没找到构造,采用默认构造,即使是私有的

创建 bean - 依赖注入

要点 总结
AutowiredAnnotationBeanPostProcessor 识别 @Autowired 及 @Value 标注的成员,封装为 InjectionMetadata 进行依赖注入
CommonAnnotationBeanPostProcessor 识别 @Resource 标注的成员,封装为 InjectionMetadata 进行依赖注入
resolveDependency 用来查找要装配的值,可以识别:① Optional;② ObjectFactory 及 ObjectProvider;③ @Lazy 注解;④ @Value 注解(${ }, #{ }, 类型转换);⑤ 集合类型(Collection,Map,数组等);⑥ 泛型和 @Qualifier(用来区分类型歧义);⑦ primary 及名字匹配(用来区分类型歧义)
AUTOWIRE_BY_NAME 根据成员名字找 bean 对象,修改 mbd 的 propertyValues,不会考虑简单类型的成员
AUTOWIRE_BY_TYPE 根据成员类型执行 resolveDependency 找到依赖注入的值,修改 mbd 的 propertyValues
applyPropertyValues 根据 mbd 的 propertyValues 进行依赖注入(即xml中 <property name ref|value/>

创建 bean - 初始化

要点 总结
内置 Aware 接口的装配 包括 BeanNameAware,BeanFactoryAware 等
扩展 Aware 接口的装配 由 ApplicationContextAwareProcessor 解析,执行时机在 postProcessBeforeInitialization
@PostConstruct 由 CommonAnnotationBeanPostProcessor 解析,执行时机在 postProcessBeforeInitialization
InitializingBean 通过接口回调执行初始化
initMethod 根据 BeanDefinition 得到的初始化方法执行初始化,即 <bean init-method> 或 @Bean(initMethod)
创建 aop 代理 由 AnnotationAwareAspectJAutoProxyCreator 创建,执行时机在 postProcessAfterInitialization

创建 bean - 注册可销毁 bean

在这一步判断并登记可销毁 bean

  • 判断依据

    • 如果实现了 DisposableBean 或 AutoCloseable 接口,则为可销毁 bean
    • 如果自定义了 destroyMethod,则为可销毁 bean
    • 如果采用 @Bean 没有指定 destroyMethod,则采用自动推断方式获取销毁方法名(close,shutdown)
    • 如果有 @PreDestroy 标注的方法
  • 存储位置
    • singleton scope 的可销毁 bean 会存储于 beanFactory 的成员当中
    • 自定义 scope 的可销毁 bean 会存储于对应的域对象当中
    • prototype scope 不会存储,需要自己找到此对象销毁
  • 存储时都会封装为 DisposableBeanAdapter 类型对销毁方法的调用进行适配

类型转换处理

  • 如果 getBean 的 requiredType 参数与实际得到的对象类型不同,会尝试进行类型转换

销毁 bean

  • 销毁时机

    • singleton bean 的销毁在 ApplicationContext.close 时,此时会找到所有 DisposableBean 的名字,逐一销毁
    • 自定义 scope bean 的销毁在作用域对象生命周期结束时
    • prototype bean 的销毁可以通过自己手动调用 AutowireCapableBeanFactory.destroyBean 方法执行销毁
  • 同一 bean 中不同形式销毁方法的调用次序
    • 优先后处理器销毁,即 @PreDestroy
    • 其次 DisposableBean 接口销毁
    • 最后 destroyMethod 销毁(包括自定义名称,推断名称,AutoCloseable 接口 多选一)

浅谈spring的生命周期相关推荐

  1. 推荐 :浅谈用户全生命周期管理

    导读: 今天我们邀请到了云音乐的张毅老师,给大家分享他对于用户全生命周期运营的思考和总结,从定义到周期划分,用户分层定义,到后续运营策略方式,系统建设.数据体系等逐步探讨. 一.用户生命周期定义 Li ...

  2. 浅谈Activity的生命周期

    Activity的生命周期 简述生命周期 onCreate 当Acitivity第一次被创建出来时会被触发,一般在这里要做的事情是创建视图等等. onStart 当activity开始运行从不可见到可 ...

  3. 浅谈Spring的Bean生命周期和作用域

    学习spring有一段时间了.有的人说Spring的发展就是Java的发展,Spring就是Java的半壁江山,而且AOP思想更是OOP思想的一种扩展和延申.所以今天来浅谈一下spring的生命周期和 ...

  4. 浅谈 Spring IOC

    浅谈 Spring IOC 什么是IOC 理解 IOC 和 DI Spring IOC 相关操作个人总结 什么是IOC Ioc-Inversion of Control,即"控制反转&quo ...

  5. 浅谈Spring定时任务

    浅谈Spring定时任务 三种定时任务基于原理 多定时任务并发配置 动态定时任务 定时任务Demo 三种定时任务基于原理 SpringBoot配置定时任务主要有Spring Schedule.JDK自 ...

  6. 浅谈Spring IOC的理解

    浅谈Spring IOC的理解 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊 ...

  7. 浅谈 Spring IOC和AOP

    浅谈 Spring IOC和AOP IOC 控制反转 以前创建对象的主动权和时机是由于自己把握的,现在将这种权利转移到Spring容器中,并且根据配置文件去创建对象管理对象 ioc的注入方式有三种:构 ...

  8. Spring的生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring的生命周期 转载于:https://my.oschina.net/u/138995/blog/176378

  9. Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02

    文章目录 Pre 通俗流程 finishBeanFactoryInitialization Pre Spring5源码 - 06 Spring Bean 生命周期流程 概述 01 接上文 通俗流程 下 ...

最新文章

  1. luogu P1280 尼克的任务 序列DP
  2. R语言使用ggplot2包使用geom_boxplot函数绘制基础分组箱图(分组箱体框颜色调色板配置)实战
  3. 【大数据-Hadoop】Spark
  4. XenDesktop 5.6 PVS6.1测试中出现的一例错误:Management Interface:Remote request failed
  5. SAP CRM IBASE头部字段valid from和valid to的填充逻辑
  6. python中二进制整数_Python程序查找表示二进制整数的必要位数
  7. shell 中去掉末尾换行符
  8. 程序员的算法课(2)-排序算法
  9. ZOJ1151 Word Reversal(没法提交)
  10. mongodb 扩展 libmongoc ssl_扩展面板
  11. Java程序员的职业规划
  12. Smobiler-ListView
  13. 五环打击理论的主要原则
  14. 基于java的网上鲜花销售系统,基于JAVA的鲜花销售管理系统MVC开发,免费分享
  15. 给出一个用逗号分隔开的字符串。求各部分之和
  16. 字符串查找函数和错误信息报告函数
  17. 数据库—行式存储和列式存储
  18. Scratch-简易时钟制作
  19. Chat Top10 | 给面试官手写一个 Nacos,多少 K?
  20. CRF用于命名实体识别(快速上手实现)

热门文章

  1. 2D MMO中角色动画的优化总结
  2. 【学习机器学习】实验——线性模型实现
  3. kcf opencv源码
  4. fps软件工作量评估示例_介绍FPS示例
  5. linux主流的web服务器,适合Web服务器的非主流Linux发行版
  6. Java版:字母的大小写转换
  7. openwrt pppoe无法自动重连
  8. | 谁懂这篇文,玩游戏还会卡顿?
  9. 计算机视觉——python在一张图中画多条ROC线
  10. pgsql sql中获取当前时间_PostgreSQL技巧 如何获取当前日期时间