面试题:什么是循环依赖(常问)?

循环依赖指的是在Spring框架中,两个或多个Bean相互依赖,形成一个闭环。例如,Bean A依赖于Bean B,而Bean B又依赖于Bean A,这就形成了循环依赖。

示例:

java

复制

@Component
public class BeanA {
    private final BeanB beanB;

    @Autowired
    public BeanA(BeanB beanB) {
        this.beanB = beanB;
    }
}

@Component
public class BeanB {
    private final BeanA beanA;

    @Autowired
    public BeanB(BeanA beanA) {
        this.beanA = beanA;
    }
}

在这个例子中,BeanA依赖于BeanB,而BeanB又依赖于BeanA,这就形成了循环依赖。

Spring如何处理循环依赖?

Spring通过三级缓存来解决循环依赖问题:

  1. Singleton Objects Cache:存放完全初始化好的Bean。
  2. Early Singleton Objects Cache:存放提前暴露的Bean(尚未完全初始化)。
  3. Singleton Factories Cache:存放Bean的工厂对象,用于创建Bean的早期引用。

解决过程:

  1. 当Spring容器创建BeanA时,发现它依赖于BeanB,于是开始创建BeanB
  2. 在创建BeanB时,发现它依赖于BeanA,此时BeanA尚未完全初始化,但Spring会将BeanA的早期引用(即半成品)放入Early Singleton Objects Cache中。
  3. BeanB通过这个早期引用完成初始化,然后BeanA再通过完全初始化的BeanB完成自己的初始化。

注意事项:

  • 构造函数注入无法解决循环依赖问题,因为构造函数注入要求所有依赖在构造时就必须准备好。
  • Setter注入字段注入可以解决循环依赖问题,因为Spring可以在Bean实例化后再注入依赖。

代码示例(Setter注入):

@Component
public class BeanA {
private BeanB beanB;
@Autowired
public void setBeanB(BeanB beanB) {
this.beanB = beanB;
}
}
@Component
public class BeanB {
private BeanA beanA;
@Autowired
public void setBeanA(BeanA beanA) {
this.beanA = beanA;
}
}
@Component
public class BeanA {
    private BeanB beanB;

    @Autowired
    public void setBeanB(BeanB beanB) {
        this.beanB = beanB;
    }
}

@Component
public class BeanB {
    private BeanA beanA;

    @Autowired
    public void setBeanA(BeanA beanA) {
        this.beanA = beanA;
    }
}
@Component public class BeanA { private BeanB beanB; @Autowired public void setBeanB(BeanB beanB) { this.beanB = beanB; } } @Component public class BeanB { private BeanA beanA; @Autowired public void setBeanA(BeanA beanA) { this.beanA = beanA; } }

通过Setter注入,Spring可以在Bean实例化后再注入依赖,从而解决循环依赖问题。

总结:

循环依赖是Spring中常见的问题,Spring通过三级缓存机制来解决这个问题。理解循环依赖及其解决方案对于深入掌握Spring框架非常重要。

THE END
点赞14 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容