Spring Bean的生命周期是Spring面试热点问题。这个问题即考察对Spring的微观了解,又考察对Spring的宏观认识,想要答好并不容易!本文希望能够从源码角度入手,帮助面试者彻底搞定Spring Bean的生命周期。

只有四个!

是的,Spring Bean的生命周期只有这四个阶段。把这四个阶段和每个阶段对应的扩展点糅合在一起虽然没有问题,但是这样非常凌乱,难以记忆。要彻底搞清楚Spring的生命周期,首先要把这四个阶段牢牢记住。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。在这四步之间穿插的各种扩展点,稍后会讲。

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

实例化 -> 属性赋值 -> 初始化 -> 销毁

主要逻辑都在doCreate()方法中,逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。

  • createBeanInstance() -> 实例化
  • populateBean() -> 属性赋值
  • initializeBean() -> 初始化

源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。关于本文的Spring源码都将忽略无关部分,便于理解:

至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()

常用扩展点

Spring生命周期相关的常用扩展点非常多,所以问题不是不知道,而是记不住或者记不牢。其实记不住的根本原因还是不够了解,这里通过源码+分类的方式帮大家记忆。

第一大类:影响多个Bean的接口

实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

这两兄弟可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:

InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口,严格意义上来看他们不是两兄弟,而是两父子。但是从生命周期角度我们重点关注其特有的对实例化阶段的影响,图中省略了从BeanPostProcessor继承的方法。

InstantiationAwareBeanPostProcessor extends BeanPostProcessor

InstantiationAwareBeanPostProcessor源码分析:

postProcessBeforeInstantiation调用点,忽略无关代码:

可以看到,postProcessBeforeInstantiation在doCreateBean之前调用,也就是在bean实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的Bean作为代理,这也是Aop等功能实现的关键点。

postProcessAfterInstantiation调用点,忽略无关代码:

可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为boolean,返回false时可以阻断属性赋值阶段(continueWithPropertyPopulation = false;)。

关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了。

第二大类:只调用一次的接口

这一大类接口的特点是功能丰富,常用于用户自定义扩展。

第二大类中又可以分为两类:

  • Aware类型的接口
  • 生命周期接口

无所不知的Aware

Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!

Aware接口众多,这里同样通过分类的方式帮助大家记忆。

Aware接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware接口的执行顺序,能够见名知意的接口不再解释。

Aware Group1

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware

Aware Group2

  • EnvironmentAware
  • EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
  • ApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口,如下:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver {}

这里涉及到另一道面试题,ApplicationContext和BeanFactory的区别,可以从ApplicationContext继承的这几个接口入手,除去BeanFactory相关的两个接口就是ApplicationContext独有的功能,这里不详细说明。

Aware调用时机源码分析

详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的!

可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。

感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。

至于Spring为什么这么实现,应该没什么特殊的考量。也许和Spring的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring对一些新的Aware采用了扩展的方式添加。

BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。

关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。

简单的两个生命周期接口

至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。

InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。

有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。

除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。

DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。

扩展阅读: BeanPostProcessor 注册时机与执行顺序

注册时机

我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor在我们的业务Bean之前初始化完成呢?

请看我们熟悉的refresh()方法的源码,省略部分无关代码:

可以看出,Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization初始化我们的单例非懒加载的Bean。

执行顺序

BeanPostProcessor有很多个,而且每个BeanPostProcessor都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered

PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序,Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序

都没有实现是三等公民,最后执行。

在以下源码中,可以很清晰的看到Spring注册各种类型BeanPostProcessor的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。

根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。

/*** Useful constant for the highest precedence value.* @see java.lang.Integer#MIN_VALUE*/int HIGHEST_PRECEDENCE = Integer.MIN_VALUE;/*** Useful constant for the lowest precedence value.* @see java.lang.Integer#MAX_VALUE*/int LOWEST_PRECEDENCE = Integer.MAX_VALUE;

PriorityOrdered、Ordered接口作为Spring整个框架通用的排序接口,在Spring中应用广泛,也是非常重要的接口。

总结

Spring Bean的生命周期分为四个阶段和多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean。整理如下:

四个阶段

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

多个扩展点

影响多个Bean

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

影响单个Bean

Aware

  • Aware Group1
  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware
  • Aware Group2
  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ApplicationContextAware(ResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAware)

生命周期

  • InitializingBean
  • DisposableBean

转载于:https://my.oschina.net/u/3159571/blog/3064640

面试-Spring的生命周期相关推荐

  1. Spring Bean 生命周期之“我从哪里来”?懂得这个很重要

    Spring bean 的生命周期很容易理解.实例化 bean 时,可能需要执行一些初始化以使其进入可用 (Ready for Use)状态.类似地,当不再需要 bean 并将其从容器中移除时,可能需 ...

  2. Spring的生命周期

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

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

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

  4. Spring Bean默认配置为单实例 Spring Bean生命周期

    2019独角兽企业重金招聘Python工程师标准>>> Spring 的Bean默认的是单例的. 如果不想单例需要如下配置: <bean id="user" ...

  5. Spring框架:三种Spring Bean生命周期技术

    当使用术语"生命周期"时,Spring的家伙指的是您的bean的构造和破坏,通常这与Spring Context的构造和破坏有关. 在某些情况下,Bean生命周期的管理不是一件容易 ...

  6. spring bean生命周期_Spring中bean的生命周期和扩展点有哪些?

    前言 今天和大家分享一下Spring中Bean的生命周期的一些知识.先来说一下什么是生命周期吧,生命周期从其语义上理解就是一个对象从产生到销毁的整个过程,之所以把这个过程称为生命周期是因为其就像一个生 ...

  7. Spring Bean生命周期: Bean的实例化

    [Spring Bean 生命周期系列]传送门 1.Spring Bean生命周期: Bean元信息的配置与解析阶段 2.Spring Bean生命周期: Bean的注册 3.Spring Bean生 ...

  8. Spring Bean生命周期过程

    Spring Bean生命周期过程 Spring Bean生命周期指的是Bean加载Spring容器的过程,单例的Bean与多例的Bean加载过程是不一样的.这里指的是单例Bean的加载过程. 图:S ...

  9. Spring容器生命周期--Lifecycle

    原文网址:Spring容器生命周期--Lifecycle_IT利刃出鞘的博客-CSDN博客 简介 Bean的初始化方法和销毁方法是Bean生命周期级别的:而Lifecycle是容器生命周期级别的.如果 ...

最新文章

  1. mysql5.6热升级_mysql 5.6 后热数据的加载
  2. Revit二次开发之“使用ElementTransformUtils.MoveElement()移动元素”
  3. 【区块链与未来】区块链技术将重塑我们的世界
  4. flutter进度条
  5. 设计买什么笔记本电脑_大一设计专业新生,买什么牌子笔记本电脑合适?
  6. 牛客-139 I. Substring(后缀数组 or 后缀自动机)
  7. java xfire webservice client_Xfire调用 webservice封装
  8. Angular ngTemplateOutlet 元素的学习笔记
  9. C#/VB.NET 复制Excel中的指定单元格区域
  10. Kaggle新上比赛:胸部X光片肺炎检测
  11. 终于换了杀毒工具(NOD32教育网升级)
  12. 解决An attempt was made to load a program with an incorrect format.问题
  13. angular 居中_Angular Material design设计
  14. creo管道设计教程_Creo7.0设计探索在管道设计的应用
  15. 汇编语言编写Hello World
  16. 如何将pdf拆分为单页?推荐这些方法
  17. [VC] 【Visual Studio】2005~2015中文完整旗舰版(附序列号)
  18. 与百度文心玩文字冒险游戏[寻五宝石]
  19. 导师姻缘牵线,这对博士夫妻:累计一作发15篇论文,毕业留校任教!
  20. 我的世界Java版最大村庄_我的世界:java版完美种子,开局两村庄齐铁套

热门文章

  1. vue使用computed有参数_【Vue原理】Computed - 源码版
  2. shell中的 中文和英文 双引号
  3. 当小米Pay碰见Apple Pay!中国银联宣布同小米深度合作
  4. Java开发和测试开发两个岗位应该选哪个?
  5. Android SDK怎么救砖,z怎么样用android sdk救砖
  6. 「Game Jam 厦门站」更多细节公开,这就是传说中的排面?!
  7. Mysql数据库中的各种锁
  8. QQ2 微信红包java
  9. 使用hadoop实现ip地理位置统计~ip归属地和运营商
  10. 快递查询API调用,获得物流单号的跟踪信息