Bean实例化过程以及循环依赖
1. Bean创建
1. 实例化Bean
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,便实例化所有的bean。容器通过获取BeanDefinition对象中的信息进行实例化。并且这一步仅仅是简单的实例化,仅仅利用构造函数通过反射实例化出对象,并未进行依赖注入。
2. 依赖注入
实例化后的对象被封装在BeanWrapper对象中,并且此时对象仍然是一个原生的状态,并没有进行依赖注入。紧接着Spring根据BeanDefinition中的信息进行依赖注入。并且通过BeanWrapper提供的设置属性的接口完成依赖注入。如果此Bean的属性的类型被注册了属性编辑器则会通过属性编辑器实例化属性。
3. Aware接口
紧接着,Spring会检测该对象是否实现了xxxAware接口,并调用相关的xxxAware实例的方法,这里的xxxAware有:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。
4. BeanPostProcessor前置处理器
接口BeanPostProcessor的方法postProcessBeforeInitialzation( Object bean, String beanName)开始执行。此方法返回bean实例,也就是说这里有机会更换实例,如果这里返回null则后面的BeanPostProcessor均不再进行下去。
5 InitializingBean、init-method
如果bean实现了InitializingBean接口或者指定了init-method,则afterPropertiesSet()或者指定初始化方法执行。
6 BeanPostProcessor后置处理器
接口BeanPostProcessor的方法postProcessAfterInitialization( Object bean, String beanName)开始执行。此方法返回bean实例,也就是说这里有机会更换实例,如果这里返回null则后面的BeanPostProcessor均不再进行下去。
4,5,6过程实现如下:
1,applyBeanPostProcessorsBeforeInitialization(Object bean, String beanName)
2,invokeInitMethods(String, Object bean, RootBeanDefinition mbd)
3,applyBeanPostProcessorsAfterInitialization(Object bean, String beanName)
7. DisposableBean和destroy-method
注册DisposableBean,当调用Context的close()方法时,如果bean实现了DisposableBean接口则会调用其destroy()方法,如果bean指定了destroy-method属性则会调用其指定的方法,如果二者都有则都会调用,如果destroy-method属性值为(inferred)则close()和shutdown()方法被调用。注意:这个只针对scope为singleton的bean,对于scope为prototype的bean不存在销毁的说法。
8. FactoryBean
如果bean实现了FactoryBean接口则会调用getObject()方法返回bean.
2. 循环依赖
1. A、B互相依赖且彼此均通过构造函数注入,则spring直接抛BeanCurrentlyInCreationException异常。
2. prototype bean之间不允许循环依赖,原理:
当创建prototype bean时会先在ThreadLocal中找此bean的name是否存在如果存在则直接异常。例如:A、B都为prototype且相互依赖,则创建流程为:
- 创建A对象,创建A对象前会判断是否已经创建,判断方法为在Thread Local对象中查找A名称是否存在,第一次不存在所以此时把A名称缓存至ThreadLocal。
- A创建的过程中发现依赖B,则开始创建B,B名称缓存至ThreadLocal。
- B创建的过程中发现依赖A,则开始创建A,此时发现ThreadLocal已经缓存了A则直接抛出异常。
如下图:
image
2. 单例默认无参构造函数允许循环依赖,其实现原理为三级缓存:
- 构造函数实例化完成后缓存至singletonFactories集合,此时虽然没有完全走完实例化流程但是可以被其他bean注入。
- 在依赖注入阶段第一次被其他bean注入则缓存至earlySingletonObjects并移除singletonFactories缓存。
- 最后创建完成缓存至singletonObjects集合并移除earlySingletonObjects缓存。
例如有这样的依赖关系:A依赖B、C,B、C依赖A。那么其创建过程如下:
- 请求A,在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找,发现没有。
- 开始创建A,先执行构造函数实例化A,把A缓存至singletonFactories中。
- A注入B,请求B,其过程同第1步请求A的过程。
- B注入A,请求A,此时A处于依赖注入阶段并且第一次在此阶段被请求,此时在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找A,发现singletonFactories中存在A(第2步放进去的),此时将A从singletonFactories中移除并且缓存至earlySingletonObjects中,然后返回给B。
- B注入A结束,B创建结束,A注入B结束。
- A注入C,C的构成过程同B。
- C注入A,请求A,此时在集合singletonObjects、earlySingletonObjects、singletonFactories中依次查找,当找到earlySingletonObjects时发现已经存在了(第4步中放进去的),直接将A返回给C。
- C注入A结束,C创建结束,A注入C结束。
- 从earlySingletonObjects集合中移除A并缓存至singletonObjects。至此A、B、C创建完成。