三级循环解决循环依赖
首先我们要理解什么是依赖缓存?
简单来说,假如这里有两个类:AService 和 BService 两个Bean对象。并且做测试方法
@Component
public class AService{
@Autowire
private BService bService;
public void test(){
System.out.println(bService);
}
}
@Component
public class BService{
@Autowire
private AService aService;
}
public class Test{
public static void main(String[] args) {
// 这里new了一个Spring容器出来
AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(AppConfig.class);
// 然后从容器中获取Bean对象出来
AService aService = (AService)application.getBean("AService");
// 然后执行Bean对象的方法
aService.test();
}
}
这里我们需要注意就是为什么可以从Spring获取到这个Bean对象出来呢?
想要获得AService的完整Bean对象,就需要填充BService的属性,此时AService就会去单例池(一级缓存)中去寻找BService的Bean对象出来给AService赋值。发现,单例池中没有BService的Bean对象,所以就需要去创建BService的Bean对象。BService也需要像AService一样执行上图的实例化操作。那么获得BService对象后,发现单例池也没有AService对象。难道又需要去创建AService对象执行上图操作吗?以上描述就是 循环依赖。(图片流程如下图)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vP4zQija-1672237936849)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]
那么如何解决这个循环依赖问题?
先放出一个完整的流程图
单例池的效果(ConcurrentHashMap)?
就是你在需要在获取Spring容器里面的一个对象的时候获取到的Bean对象是同一个,你比如说输入的是 容器.getBean("AService");
,你将获取到的永远是同一个Bean对象。这就是所谓的单例池的作用。
同时我们要知道,代理对象中肯定是有个属性指向这个普通对象的。
扩展:啥情况的循环依赖是Spring不能解决呢?
假如上面的AService和BService中没有假如@Autowire注解,那么就不能用Spring解决了。(可以假如**@lazy**注解实现)
@Component
public class AService{
private BService bService;
public AService(BService bService) {
this.bService = bService;
}
public void test(){
System.out.println(bService);
}
}
@Component
public class BService{
private AService aService;
public BService(AService aService) {
this.aService = aService;
}
}
因为你对AService进行实例化的时候,需要注入BService的Bean对象,但此时BService对象都没有创建Bean出来,那好了,需要去重新创建AService对象。这不又是循环依赖了嘛?
总结
三级缓存的作用是破解这个循环依赖问题。
用到的集合缓存有:
一级缓存作用(singletonObjects–ConcurrentHashMap):单例池;用来存放实现了完整生命周期的Bean对象,通过getBean()方法通过相同名字拿到同一个对象。
二级缓存作用(earlySingletonObjects–ConcurrentHashMap):用来保存 那些出现循环依赖的且需要提前暴露给其他的Bean对象用(比如在AService的Bean生命周期中填充BService属性时需要用到AService的代理对象) 的单例Bean对象的缓存。(有多个Bean依赖循环,就可以给每个Bean属性提供同一个代理对象)
三级缓存作用(singletonFactories–HashMap):用来存放Bean的普通对象,后面第二步需要要到Bean的普通对象来实现AOP。
性提供同一个代理对象)
三级缓存作用(singletonFactories–HashMap):用来存放Bean的普通对象,后面第二步需要要到Bean的普通对象来实现AOP。
creatingSet:用来给后面步骤2的时候判断该对象是否正在进行了循环依赖。