本篇是接着bean的创建基本流程,后置处理器的的续写,了解本篇的Bean的生命周期需要熟悉bean创建的基本过程和后置处理器
Bean的创建基本流程:http://t.csdn.cn/9nfTE
后置处理器详解:http://t.csdn.cn/PjMYc
最后,文章部分为个人的总结与思考,如果遗漏欢迎指正或补充,感谢您的阅览,愿您终有所获
先来简单回顾一下bean的实例化步骤
bean的实例化步骤总共5步
1.将bean的配置信息封装成一个BeanDefinition对象
2.把所有的BeanDefinition对象存储到beanDefinitionMap的Map集合中
3.Spring框架再对该Map进行遍历,取出每个BeanDefinition对象的配置信息,通过反射创建bean
4.创建好的Bean对象存储在一个名为singletonObjects(单例池,也在BeanFactory中维护)的Map集合中
5.当调用getBean方法最终从该Map集合中取出Bean实例对象返回
而bean的生命周期是在bean实例化后,即通过反射创建对象那时开始,到注入属性,成为一个完整的bean,最后存储到单例池中,这个过程称为bean的生命周期
bean的生命周期大致分为三个阶段:
1 Bean的实例化阶段
2 Bean的初始化阶段
3 Bean的完成阶段
下面就会对这3个阶段做详细分解
Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton(单例)的,是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化
Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,Spring的注解功能等
spring高频面试题Bean的循环引用问题都是在这个阶段体现的
Spring Bean的初始化过程涉及如下几个过程:
①Bean实例的属性填充(就是通过BeanDefinition中封装的bean的属性信息set到bean里)
下面是BeanDefinition中封装的bean的属性位置,上图看印象更深刻
Bean实例属性填充几种情况
Spring在进行属性注入时,会分为如下几种情况:
②Aware接口属性注入(当有些bean实现一些扩展接口,需要什么对象,框架就通过Aware接口规定的方法注入进去,在这里不是重点)
③BeanPostProcessor的before()方法回调(bean的后处理器的重写方法)
④InitializingBean接口的初始化方法回调
⑤自定义初始化方法init回调
⑥BeanPostProcessor的after()方法回调(bean的后处理器的重写方法)
经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池singletonObjects中去了,即完成了Spring Bean的整个生命周期。
循环依赖发生时机是在Bean实例属性填充时
多个实体之间相互依赖并形成闭环的情况就叫做"循环依赖",也叫做"循环引用"
属性互相注入,导致无法创建完整的bean对象,上图更形象的展示了B依赖A注入,A依赖B注入的情况,结果形成闭环
循环依赖图解过程
Spring提供了三级缓存存储 完整Bean实例 和 半成品Bean实例 ,用于解决循环引用问题
在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:
public class DefaultSingletonBeanRegistry ... {
//1、最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean,称之为"一级缓存"
Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
//2、早期Bean单例池,缓存半成品对象,且当前对象已经被其他对象引用了,称之为"二级缓存"
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
//3、单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean,称之为"三级缓存"
Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
可以看看它在源码的位置
三级缓存详细图解原理
下面图解给的注释很详细,按步骤来,细看就会发现是如何用三级缓存解决循环依赖的问题的,看懂了就是醍醐灌顶
UserService和UserDao循环依赖的过程结合上述三级缓存描述一下
当然,如果有兴趣去底层翻阅源码查看其中调用过程和实习方式可以根据黑马的调用流程图来翻阅,避免迷失在源码中,反正翻源码时务必目的明确,别贪。
三级缓存源码调用流程图:https://pan.baidu.com/s/1jwruaz9NmFN9sFHf6Ksrqw?pwd=sohp
提取码:sohp