什么是循环依赖?
- 通俗的讲就是N个bean相互引用对方,最终形成闭环。
循环依赖会产生什么问题?
- Bean无法成功注入,导致业务无法进行
- 产生死循环
Spring中解决循环依赖的方式?
-
使用注解@Lazy
image.png -
setter方式注入
image.png -
@PostConstruct
image.png -
实现ApplicationContextAware与InitializingBean
image.png
Spring整个解决循环依赖问题的实现思路
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
Spring二级缓存可以解决循环依赖吗?
1. 一级缓存能解决吗?
只有一级缓存并不是不能解决循环依赖。因为 A 的成品创建依赖于 B,B的成品创建又依赖于 A,当需要补全B的属性时 A 还是没有创建完,所以会出现死循环。
2. 二级缓存能解决吗?
有了二级缓存已经能解决循环依赖了。一个缓存用于存放成品对象,另外一个缓存用于存放半成品对象。A 在创建半成品对象后存放到缓存中,接下来补充 A 对象中依赖 B 的属性。B 继续创建,创建的半成品同样放到缓存中,在补充对象的 A 属性时,可以从半成品缓存中获取,现在 B 就是一个完整对象了,而接下来像是递归操作一样 A 也是一个完整对象了。
3. 三级缓存解决什么?
有了二级缓存都能解决 Spring 依赖了,怎么要有三级缓存呢。其实我们在前面分析源码时也提到过,三级缓存主要是解决 Spring AOP 的特性。AOP 本身就是对方法的增强,是 ObjectFactory<?> 类型的 lambda 表达式,而 Spring 的原则又不希望将此类类型的 Bean 前置创建,所以要存放到三级缓存中处理。其实整体处理过程类似,唯独是 B 在填充属性 A 时,先查询成品缓存、再查半成品缓存,最后在看看有没有单例工程类在三级缓存中。最终获取到以后调用 getObject 方法返回代理引用或者原始引用。至此也就解决了 Spring AOP 所带来的三级缓存问题。