Spring源码分析:非懒加载的单例Bean初始化过程(下)
2017-08-21 15:22
796 查看
上文Spring源码分析:非懒加载的单例Bean初始化过程(上),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的。先贴一下AbstractAutowireCapableBeanFactory的doCreateBean方法代码:
下面继续分析初始化一个Bean的流程,不太重要的流程就跳过了。
属性注入
属性注入的代码比较好找,可以看一下40行,取名为populateBean,即填充Bean的意思,看一下代码实现:
这段代码层次有点深,跟一下74行的applyPropertyValues方法,最后那个pvs的实现类为MutablePropertyValues,里面持有一个List<PropertyValue>,每一个PropertyValue包含了此Bean属性的属性名与属性值。74行的代码实现为:
之后在第41行~第76行做了一次深拷贝(只是名字叫做深拷贝而已,其实就是遍历PropertyValue然后一个一个赋值到一个新的List而不是Java语义上的Clone,这里使用深拷贝是为了解析Values值中的所有引用),将PropertyValue一个一个赋值到一个新的List里面去,起名为deepCopy。最后执行83行进行复制,bw即BeanWrapper,持有Bean实例的一个Bean包装类,看一下代码实现:
这段代码没什么特别的,遍历前面的deepCopy,拿每一个PropertyValue,执行第12行的setPropertyValue:
找一个合适的BeanWrapper,这里就是自身,然后执行17行的setPropertyValue方法进入最后一步,方法非常长,截取核心的一段:
大致流程就是两步:
(1)拿到写方法并将方法的可见性设置为true
(2)拿到Value值,对Bean通过反射调用写方法
这样完成了对于Bean属性值的设置。
Aware注入
接下来是Aware注入。在使用Spring的时候我们将自己的Bean实现BeanNameAware接口、BeanFactoryAware接口等,依赖容器帮我们注入当前Bean的名称或者Bean工厂,其代码实现先追溯到上面doCreateBean方法的42行initializeBean方法:
看一下上面第5行的实现:
看到这里判断,如果bean是BeanNameAware接口的实现类会调用setBeanName方法、如果bean是BeanClassLoaderAware接口的实现类会调用setBeanClassLoader方法、如果是BeanFactoryAware接口的实现类会调用setBeanFactory方法,注入对应的属性值。
调用BeanPostProcessor的postProcessBeforeInitialization方法
上面initializeBean方法再看16行其实现:
遍历每个BeanPostProcessor接口实现,调用postProcessBeforeInitialization方法,这个接口的调用时机之后会总结,这里就代码先简单提一下。
调用初始化方法
initializeBean方法的20行,调用Bean的初始化方法,看一下实现:
看到,代码做了两件事情:
1、先判断Bean是否InitializingBean的实现类,是的话,将Bean强转为InitializingBean,直接调用afterPropertiesSet()方法
2、尝试去拿init-method,假如有的话,通过反射,调用initMethod
因此,两种方法各有优劣:使用实现InitializingBean接口的方式效率更高一点,因为init-method方法是通过反射进行调用的;从另外一个角度讲,使用init-method方法之后和Spring的耦合度会更低一点。具体使用哪种方式调用初始化方法,看个人喜好。
调用BeanPostProcessor的postProcessAfterInitialization方法
最后一步,initializeBean方法的29行:
同样遍历BeanPostProcessor,调用postProcessAfterInitialization方法。因此对于BeanPostProcessor方法总结一下:
1、在初始化每一个Bean的时候都会调用每一个配置的BeanPostProcessor的方法
2、在Bean属性设置、Aware设置后调用postProcessBeforeInitialization方法
3、在初始化方法调用后调用postProcessAfterInitialization方法
注册需要执行销毁方法的Bean
接下来看一下最上面doCreateBean方法的第83行registerDisposableBeanIfNecessary(beanName, bean, mbd)这一句,完成了创建Bean的最后一件事情:注册需要执行销毁方法的Bean。
看一下方法的实现:
其中第3行第一个判断为必须不是prototype(原型)的,第二个判断requiresDestruction方法的实现为:
要注册销毁方法,Bean需要至少满足以下三个条件之一:
(1)Bean是DisposableBean的实现类,此时执行DisposableBean的接口方法destroy()
(2)Bean标签中有配置destroy-method属性,此时执行destroy-method配置指定的方法
(3)当前Bean对应的BeanFactory中持有DestructionAwareBeanPostProcessor接口的实现类,此时执行DestructionAwareBeanPostProcessor的接口方法postProcessBeforeDestruction
在满足上面三个条件之一的情况下,容器便会注册销毁该Bean,注册Bean的方法很简单,见registerDisposableBean方法实现:
容器销毁的时候,会遍历disposableBeans,逐一执行销毁方法。
流程总结
本文和上篇文章分析了Spring Bean初始化的步骤,最后用一幅图总结一下Spring Bean初始化的流程:
图只是起梳理流程作用,抛砖引玉,具体代码实现还需要网友朋友们照着代码自己去一步一步分析。
属性注入
属性注入的代码比较好找,可以看一下40行,取名为populateBean,即填充Bean的意思,看一下代码实现:
(1)拿到写方法并将方法的可见性设置为true
(2)拿到Value值,对Bean通过反射调用写方法
这样完成了对于Bean属性值的设置。
Aware注入
接下来是Aware注入。在使用Spring的时候我们将自己的Bean实现BeanNameAware接口、BeanFactoryAware接口等,依赖容器帮我们注入当前Bean的名称或者Bean工厂,其代码实现先追溯到上面doCreateBean方法的42行initializeBean方法:
调用BeanPostProcessor的postProcessBeforeInitialization方法
上面initializeBean方法再看16行其实现:
调用初始化方法
initializeBean方法的20行,调用Bean的初始化方法,看一下实现:
1、先判断Bean是否InitializingBean的实现类,是的话,将Bean强转为InitializingBean,直接调用afterPropertiesSet()方法
2、尝试去拿init-method,假如有的话,通过反射,调用initMethod
因此,两种方法各有优劣:使用实现InitializingBean接口的方式效率更高一点,因为init-method方法是通过反射进行调用的;从另外一个角度讲,使用init-method方法之后和Spring的耦合度会更低一点。具体使用哪种方式调用初始化方法,看个人喜好。
调用BeanPostProcessor的postProcessAfterInitialization方法
最后一步,initializeBean方法的29行:
1、在初始化每一个Bean的时候都会调用每一个配置的BeanPostProcessor的方法
2、在Bean属性设置、Aware设置后调用postProcessBeforeInitialization方法
3、在初始化方法调用后调用postProcessAfterInitialization方法
注册需要执行销毁方法的Bean
接下来看一下最上面doCreateBean方法的第83行registerDisposableBeanIfNecessary(beanName, bean, mbd)这一句,完成了创建Bean的最后一件事情:注册需要执行销毁方法的Bean。
看一下方法的实现:
(1)Bean是DisposableBean的实现类,此时执行DisposableBean的接口方法destroy()
(2)Bean标签中有配置destroy-method属性,此时执行destroy-method配置指定的方法
(3)当前Bean对应的BeanFactory中持有DestructionAwareBeanPostProcessor接口的实现类,此时执行DestructionAwareBeanPostProcessor的接口方法postProcessBeforeDestruction
在满足上面三个条件之一的情况下,容器便会注册销毁该Bean,注册Bean的方法很简单,见registerDisposableBean方法实现:
流程总结
本文和上篇文章分析了Spring Bean初始化的步骤,最后用一幅图总结一下Spring Bean初始化的流程:
图只是起梳理流程作用,抛砖引玉,具体代码实现还需要网友朋友们照着代码自己去一步一步分析。
相关文章推荐
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
- Spring源码分析:非懒加载的单例Bean初始化过程(上)
- 【Spring源码分析】非懒加载的单例Bean初始化过程(上篇)
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
- spring容器初始化,bean加载生成过程,源码解析学习
- 分析spring源码第五(三)篇:Spring中Bean的解析、加载、创建 过程总结
- 【spring源码分析】加载bean过程(1)
- spring源码分析 加载bean过程
- 【spring源码分析】加载bean过程(2)
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
- 【Spring源码分析】Bean加载流程概览
- spring源码分析-配置文件加载过程
- spring boot实战(第十篇)Spring boot Bean加载源码分析
- spring启动component-scan类扫描加载过程---源码分析
- spring启动加载过程源码分析
- spring 加载bean过程源码简易解剖(转载)
- 【Spring源码分析系列】bean的加载
- spring启动component-scan类扫描加载过程---源码分析
- SSH 之 Spring的源码(一)——Bean加载过程
- Spring bean 标签加载、解析过程分析