Spring三级缓存解决循环依赖
Spring三级缓存解决循环依赖
Spring中Bean的生命周期
1.实例化
2.属性赋值
3.初始化
5.销毁
为什么要提到Bean的生命周期呢,是因为循环依赖就是发生在属性依赖注入阶段,即使用@Automated
注解,如果没有使用@Automated
,其实我们的AService对象中的bService对象的值是null,BService对象中aService的值也是null。
单例Bean对象初始化完成后将会放到单例池中singletonObjects
,这就是Spring中的一级缓存。
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
什么是循环依赖
1.AService实例化
2.AService给属性bService对象赋值(从单例池中找如果没有则走创建流程)
--2.1 BService实例化
--2.2 BService给属性aService对象赋值(从单例池中找如果没有则走创建流程)
--2.3 BService对象初始化
--2.4 BService对象存入单例池singletonObjects
中
--2.5 BService对象销毁
3.AService对象初始化
4.AService对象存入单例池singletonObjects
中
5.AService对象销毁
创建AService对象的属性赋值阶段,需要给bService对象赋值时,此时从单例池singletonObjects
中找不到bService对象,然后走创建bService对象的流程,再创建bService对象的属性赋值阶段,又需要aService对象,此时从单例池singletonObjects
中还是找不到,就又走创建aService对象,这样就导致死循环了,这就是Spring中的循环依赖问题。
代码中的循环依赖如下:
AService.java
@Component
public class AService {
@Autowired
private BService bService;
}
BService.java
@Component
public class BService {
@Autowired
private AService aService;
}
如何解决循环依赖(打破循环)
加一层,如果加一层解决不了的话就再加一层。
这里的加一层是指加一层缓存,上述中只涉及一个缓存即一级缓存单例池singletonObjects
,存储的是初始化完成的Bean对象。
那可以通过加一层缓存来存储只实例化完成(即new完的对象),但属性还没有进行赋值的半成品Bean对象。earlySingletonObjects
。
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
AService对象实例化完成后就加入到earlySingletonObjects
中,当BService给属性aService属性赋值时,还是先从就可以从singletonObjects
中获取发现获取不到,然后就从earlySingletonObjects
获取,可以获取到,这样就打破了循环,BService对象先创建完成,然后将创建完成的BService对象赋值给AService对象中bService属性。
注意:上面虽然可以解决循环依赖的问题,但Spring中并不是这么解决的,而是通过引入三级缓存来解决的。
Spring中是如何解决循环依赖的(引入三级缓存)
三级缓存存储的是Lambda表达式,用于保存当前正在创建对象的一个函数式接口ObjectFactory
,此时并不会直接创建该对象,当从singletonFactories
getObj的时候才会执行创建。
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
原理
在创建AService对象时会将创建aService对象的Lambda表达式加入到三级缓存singletonFactories
中
在创建BService对象给其aService属性赋值时,先从一级缓存单例池中获取完整的bean对象,获取不到从二级缓存中获取未初始化完成的bean对象,还是获取不到的话就从三级缓存中获取aService对象,从三级缓存中是肯定可以获取到的,因为在实例化完就加入了三级缓存。
从三级缓存中获取的可能是普通的属性对象,也可能是代理对象,这取决于是否开启了AOP并且有切点通知
Return whether the given bean is to be proxied, what additional advices (e.g. AOP Alliance interceptors) and advisors to apply
关键代码
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
- 将Lambda表达式加入到三级缓存
singletonFactories
中
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory - 加入的三级缓存的是普通对象还是代理对象
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary - 填充属性(byName和byType)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean - 从一级缓存、二级缓存、三级缓存中找依赖的bean对象
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
- 本文标签: Spring
- 本文链接: https://www.it1997.com/article/122
- 版权声明: 本文由小陈没烦恼原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权