在面试的时候,稍微高级一点的面试官,经常会问你对框架的源码掌握程度,而大部分会问你Spring,而关于Spring的问题,大多数会问到

Spring中IOC容器管理Bean的生命周期。如果没有仔细阅读过Spring源码的同学是很难讲这个问题彻底说清楚的,如果只是从一些论坛看过类似的文章

虽然有短期效果流程能说出来,但其实并没有掌握,因为其内心还没有一个直线能把断断续续的知识点给串联起来,所以很容易忘记。为了讲清楚这部分

内容,小编在前3篇文章中已经做了大量的铺垫工作。

1. 第一篇我们讲了xml配置文件是如何被Spring给读取成Java对象也就是解析XML为DocumentSpringframework学习(一)之Xml配置文件加载

2. 第二篇我们讲了Document是如何被Spring的解析器解析成Bean的元数据BeanDefinitionSpringframework学习(二)之BeanDefinition注册

3. 第三篇我们又讲了Spring是如何给我们开发者提供切入点去最后调整读取到的BeanDefinitionSpringframework-ioc学习(三)之最后修改BeanDefinition的机会

那么这篇我们就要开始讲BeanDefinition是如何被转换成Bean对象及Bean对象的生命周期。

注意

感兴趣的同学,在看这篇文章的时候,建议结合源码来看,一步一步点进去看看,思考思考。

注意小编图中的注释,有些注释小编是写在图中截图分享的。

文章目录

BeanFactory是如何把BeanDefinition转换成Bean对象

属性注入,构造注入,set注入,参数注入

Bean对象的生命周期

Bean的生命周期这是一个比较形象的描述,其实①主要就是讲Bean从创建到销毁这之间的过程。②其次在Bean从创建到销毁的过程之间会

穿插Spring提供给我们供我们实现接口的类的使用讲解,在说白点就是说: Spring在Bean创建的前后给我们开发者

去操作的机会,而需要我们继承某些类才能实现这些功能,我们要知道是那些类。如果对以上两点你都清楚了,那么无论是谁

让你在讲Bean的生命周期你就可以说是完全掌握了

一.BeanFactory是如何把BeanDefinition转换成Bean对象

前面我们说了BeanDefinition是都保存在DefaultListableBeanFactory类的beanDefinitionMap方法中的。那么我们就应该知道如果要转换bean肯定要

从这个集合中去读取BeanDefinition来进行处理。

我们看下获取Bean的方法。Bean有单例模式和原型模式。单例模式是随着Spring上下文加载完成就已经转换完成的被放在DefaultSingletonBeanRegistry的singletonObjects集合中。

而原型模式是每次加载的时候都会重新去创建一个。他俩的核心实现其实是差不多的,只不过单例是一次加载完成就放到缓存中,而原型是没有使用缓存,而是每次都去创建。为了方便我们深入研究

我们把Bean设置为原型模式和懒加载,为了方便小编第一次就进去到getBean方法里面。

开始进入

其实无论是下面那个方法,调用顺序最后都是这样调用的doGetBean()

①AbstractBeanFactory.doGetBean()

② AbstractAutowireCapableBeanFactory.createBean()

③ AbstractAutowireCapableBeanFactory.doCreateBean()

④ AbstractAutowireCapableBeanFactory.populateBean()

其中123都是实例化Bean而并不会注入其依赖的Bean,(但是排除,使用构造注入的情况)而4才真正想

这个实例中去注入依赖。同时注入通过配置文件读取的配置比如下图。

下面跟着小编的步骤来探索一下。

进入doCreateBean方法(看下图注释)

populateBean实现了注入的功能,可以从ioc中获取自己需要的依赖并注入,同时可以从配置文件中拿到你的依赖的值。

initalizeBean这个方法中是调用InitializingBean的afterPropertiesSet完成用户定义的初始化方法,但是注意初始化方法Spring中有两个

第一个就是实现InitializingBean的afterPropertiesSet,接口

第二个是xml中配置init-method。判断逻辑是先判断是否实现InitializingBean接口,其次判断init-method。如果都有都执行。

,并在前后留下了接口,供开发者对Bean做修改。

到这里当Bean的依赖都注入成功,可以返回getBean了。

二.Bean对象的生命周期

其实上面就已经把Bean的生命周期说了一大半了,除了destroy没有说,其他都讲了。下面我们专门说Bean的销毁方法

destroyBeans中有我们可以学习的东西,看完之后肯定GET到一个点!

首先小编先提一个问题!

小编想问,如果你写的程序正在运行,此时你把idea突然关了,或者是ctrl+z终止了程序,此时怎么去执行销毁呢?

好了本来小编想举几个例子,github,svn等等的钩子程序,但是篇幅太长了,就不扯了。直接上代码。

这段代码在运行时候并不会立即打印,而是在小编点击关闭程序的时候才会执行。其实就是一个hook钩子程序

现在我们在Spring的源码中在找找Spring是

正常情况和非正常情况如何销毁Bean的呢?

正常情况

调用上图步骤13

看到这里我们就清楚@PreDestroy 和DisposableBean接口和xml中destroy-method用户配置的销毁方法的执行顺序了。顺便在这里提一下@PostConstruct和InitializingBean接口和xml中init-method的顺序也是一样的。都是先执行注解的@PreDestroy和@PostConstruct,然后接口DisposableBean/InitializingBean,最后才是xml中用户自己配置的。

非正常情况

非正常情况其实和正常情况的调用流程一样,只是触发的时间点不一样。非正常情况是在ctrl+z或者程序异常退出的时候去执行的。使用的技术就是上面我们演示的hook钩子程序。

我们看AbstractApplicationContext中有一个钩子线程,并提供了一个注册钩子程序的方法registerShutdownHook。说到这里相信大家都明白了吧。

喜欢的童鞋请点击关注,谢谢你的支持。 没有任何广告,纯粹分析技术,一起共同成长进步 。

查看原文 >>
相关文章