1.循环依赖发生在哪里
循环依赖发生在几个有依赖关系的实体类中。
2.循环依赖是什么
举个简单的栗子:
学生类中有班级类的外部属性,班级类中又有学生类的外部属性。
学生bean依赖于班级bean,班级bean依赖于学生bean。
当然,这是最简单的循环,只涉及到两个bean,也有较为复杂的依赖,3个bean、5个bean等等。
3.spring在加载时会发生什么
当项目启动时,创建bean的时候,因为有循环依赖,会报BeanCurrentlyInCreationException异常,如下:
在注入这两个bean的时候,考虑到几种注入方式,下面演示注解@Autowired注入,并给出解决方案
会报异常:
4.解决方法
(@Lazy)
有点懒加载的意思,就是在加载的时候不会完全初始化,而是创建一个代理,将其注入另一个bean,注入的bean只有在需要时才会创建。
只需要在beanA中加一个注解,
@lazy这个注解可以加载方法上也可以修饰在方法参数上
再去加载启动类就不会报错了。
注意:
以上的不报错是基于A、B都是单例的情况,非单例循环依赖spring无法处理。
底层:使用三级缓存处理单例模式下的循环依赖
缓存:
一级缓存:singletonObjects :完成了初始化的单例对象map
二级缓存,earlySingletonObjects:完成实例化未初始化的单例对象ma
三级缓存,singletonFactories: 单例对象工厂map,单例对象实例化完成之后会加入singletonFactories
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
简单理解就是:对于有依赖关系的bean,spring加载起来之后,调用createBeanInstance,进行bean的实例化,然后在调用addSingletonFactory,把对象放在工厂中。有循环依赖的bean,相当于还没加载完成,但可以被其他依赖这个bean的bean加载,等所有的都放在工厂之后,在根据依赖关系加载所有的依赖bean,形成一个闭环。