原创

Spring三级缓存解决循环依赖

温馨提示:
本文最后更新于 2025年01月27日,已超过 19 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我

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,此时并不会直接创建该对象,当从singletonFactoriesgetObj的时候才会执行创建。

/** 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

  1. 将Lambda表达式加入到三级缓存singletonFactories
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory
    file
  2. 加入的三级缓存的是普通对象还是代理对象
    org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
    file
  3. 填充属性(byName和byType)
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
    file
  4. 从一级缓存、二级缓存、三级缓存中找依赖的bean对象
    org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
    org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
    file
正文到此结束
本文目录