Spring如何解决循环依赖

文章目录

  • 1、什么是循环依赖
  • 2、如何解决循环依赖

1、什么是循环依赖

Spring如何解决循环依赖_第1张图片
简单来说就是,A依赖B的同时,B也依赖A,就构成了循环依赖。还有自己依赖自己的直接依赖以及多个对象之间的间接依赖
Spring能够解决的是单例的setter注入时的循环依赖,有可能解决单例的代理对象setter注入

2、如何解决循环依赖

@Service
public class A{
 
    @Autowired
    private B b;
 
    public void test1() {
    }
}
 
@Service
public class B{
 
    @Autowired
    private A a;
 
    public void test2() {
    }
}

这是一个经典的循环依赖,但是它能正常运行,得益于spring的内部机制,让我们根本无法感知它有问题,因为spring默默帮我们解决了。

我们都知道,单例 Bean 初始化完成,要经历三步:
Spring如何解决循环依赖_第2张图片
注入就发生在第二步,属性赋值,结合这个过程,Spring 通过三级缓存解决了循环依赖:

一级缓存 : Map singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例
二级缓存 : Map earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例
三级缓存 : Map> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

下面通过A依赖B,B依赖A这个例子,来一步一步分析Spring是如何解决循环依赖的:

当我们去调用 getBean()方法的时候,Spring 会先从一级缓存中去找到目标 Bean,如果发现一级缓存中没有便会去二级缓存中去找,而如果一、二级缓存中都没有找到,意味着该目标 Bean还没有实例化。于是,Spring 容器会实例化目标 Bean

A实例的初始化过程:

  1. 因为A在此之前还未被创建,且A比B提前被扫描到,于是创建 A 实例,实例化的时候把 A 对象⼯⼚放⼊三级缓存,表示 A 开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道。
  2. 开始属性注入,A 注⼊属性时,发现依赖 B,则依次从一级到三级缓存查询B,此时 B 还没有被创建出来,所以去实例化 B。
  3. 同样,B 注⼊属性时发现依赖 A,它就会从缓存里找 A 对象。依次从⼀级到三级缓存查询 A,从三级缓存通过对象⼯⼚拿到 A,发现 A 虽然不太完善,但是存在,把 A 放⼊⼆级缓存,同时删除三级缓存中的 A,此时,B 已经实例化并且初始化完成,把 B 放入⼀级缓存。
  4. 接着 A 继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的 B 对象,A 对象创建也完成,删除⼆级缓存中的 A,同时把 A 放⼊⼀级缓存
  5. 最后,⼀级缓存中保存着实例化、初始化都完成的 A、B 对象

你可能感兴趣的:(spring,java,缓存)