StringBean生命周期
1.spring启动,扫描所有的bean(注解的,xml配置的)放进spring容器中,在容器中将这写bean装换成BeanDefinition对象,放进一个map中
2.遍历这个BeanDefinitionMap
3.验证,是否懒加载,注入模型是原型还是单例 等等
4.验证后得到一个class
5.推断这个class的构造方法,一般都是默认构造方法,但是不绝对。
6.通过反射对这个class进行实例化
7. 提前暴露一个bean工厂对象
8. 填充属性 (Autowired 注解)
9. 执行各种aware接口,和生命周期回调方法
10.将bean放进单例池中
循环依赖出现的原因
@Service
public class A(){
@Autowired
private B b;
}
@Service
public class B(){
@Autowired
private A a;
}
有两个service,A 和 B,spring启动会去初始化这两个bean。当类A初始化bean的时候去填充属性,发现有个 B 类,此时A类的bean还没有生成,又要去初始化B类的bean,当到了属性填充时,发现又要去初始化A。这样就发现出现死循环了。
由于Spring bean 的生命周期很长,只有到了单例池中,才算完全初始化成功,所以会出现循环依赖。
springbean循环依赖的解决办法
springbean在初始化bean时,在实例化了对象之后,将这个对象存放进了map中。此时这个对象,还没有走完整个初始化生命周期,所以是个半对象,只是在内存空间分配了内存。
回到上面图片代码,当对A初始化的时候,实例化的对象,也就是半对象,会先放进一个map中,然后进行属性填充,此时在对B进行属性填充时,会先从单例池中取,如果没有,在从这个map中取。
为什么时三级缓存,而不是二级缓存
看上面的例子,好像两个两个缓存,一个存放半对象,一个存放完整的bean,就能完美解决循环依赖的问题。但是spring解决bean的循环依赖运用了三级缓存。
一级缓存ConcurrentHashMap<String, Object>:存放了经历了完整的初始化生命周期的bean,这是一个单例池。
二级缓存Map<String, Object>:存放了半对象,并且不用每次都去三级缓存,从工厂中取对象。
三级缓存Map<String, ObjectFactory<?>>:存放了最原始的对象,此时是个半对象,只有内存空间,没有属性填充;利于进行扩展,如增加 BeanPostProcessor ;
总结
三级缓存,是为了,不用每次都去从工厂处理数据。如果两次缓存,AOP的时候每次都产生新的代理对象,此时就需要一个缓存来存储这个代理对象。
只有单例才支持循环依赖,因为原型默认,在用的时候才回去实例化bean,而单例默认,在spring启动就实例化bean了。导致填充属性的时候会有问题。