Spring 如何解决 Bean 的循环依赖(循环引用)

@Component
public class A {
    
    @Autowired
    private B b;
    
}
@Component
public class B {
    
    @Autowired
    private A a;
    
}

上面的情况就是 循环依赖

Bean的创建初始化过程如下

Spring 如何解决 Bean 的循环依赖(循环引用)_第1张图片

如果不采取措施,那么循环依赖就会进入死循环

但 Spring 已经帮我们解决了大部分循环依赖问题

具体是如何解决的?

Spring解决循环依赖是通过三级缓存,对应的三级缓存如下所示:

Spring 如何解决 Bean 的循环依赖(循环引用)_第2张图片

缓存名称

源码名称

作用

一级缓存

singletonObjects

单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象

二级缓存

earlySingletonObjects

缓存早期的bean对象(生命周期还没走完)

三级缓存

singletonFactories

缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的

下图是Bean的生命周期,我们依照Bean的生命周期来说明,关于Bean的生命周期可以参考我的另外一篇博客

http://t.csdn.cn/DZz5zhttp://t.csdn.cn/DZz5z

Spring 如何解决 Bean 的循环依赖(循环引用)_第3张图片

一级缓存 存放 已经全部完成的Bean,可以直接使用

二级缓存 存放 早期的bean对象,其生命周期还没走完,也就是仅通过构造函数创建出实例,但未进行依赖注入及其以下初始化步骤

三级缓存 存放 对象工厂,对象工厂用于创建对象,其具体作用下面会说明

实际上 一级 和 二级 缓存就能解决一般的 循环依赖问题

Spring 如何解决 Bean 的循环依赖(循环引用)_第4张图片

但是 如果一个对象被增强了,即 是个代理对象, 这个时候就需要一个三级缓存

Spring 如何解决 Bean 的循环依赖(循环引用)_第5张图片 

 

但是 仍有些循环引用 Spring 解决不了,这时候需要手动解决,最典型的就是 构造方法出现了循环依赖,如下

@Component
public class A {

    // B成员变量
    private B b;

    public A(B b){
        System.out.println("A的构造方法执行了...");
        this.b = b ;
    }
}
@Component
public class B {

    // A成员变量
    private A a;

    public B(A a){
        System.out.println("B的构造方法执行了...");
        this.a = a ;
    }
}

解决办法 -- 延迟加载:

public A(@Lazy B b){
    System.out.println("A的构造方法执行了...");
    this.b = b ;
}

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