《深入浅出Spring》Spring循环依赖

什么是循环依赖?

这个很好理解,多个bean之间相互依赖,形成了一个闭环。

比如:A依赖于B、B依赖于C、C依赖于A。

代码中表示:

public class A{
   
    B b;
}
public class B{
   
    C c;
}
public class C{
   
    A a;
}

如何检测是否存在循环依赖?

检测循环依赖比较简单,使用一个列表来记录正在创建中的bean,bean创建之前,先去记录中看一下自己是否已经在列表中了,如果在,说明存在循环依赖,如果不在,则将其加入到这个列表,bean创建完毕之后,将其再从这个列表中移除。

源码方面来看一下,spring创建单例bean时候,会调用下面方法

protected void beforeSingletonCreation(String beanName) {
   
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
   
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

singletonsCurrentlyInCreation就是用来记录目前正在创建中的bean名称列表,this.singletonsCurrentlyInCreation.add(beanName)返回false,说明beanName已经在当前列表中了,此时会抛循环依赖的异常BeanCurrentlyInCreationException,这个异常对应的源码:

public BeanCurrentlyInCreationException(String beanName) {
   
        super(beanName,
                "Requested bean is currently in creation: Is there an unresolvable circular reference?");
    }

上面是单例bean检测循环依赖的源码,再来看看非单例bean的情况。

以prototype情况为例,源码位于org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法中,将主要代码列出来看一下:

//检查正在创建的bean列表中是否存在beanName,如果存在,说明存在循环依赖,抛出循环依赖的异常

if (isPrototypeCurrentlyInCreation(beanName)) {
   
    throw new BeanCurrentlyInCreationException(beanName);
}
//判断scope是否是prototype
if (mbd.isPrototype()) {
   
    Object prototypeInstance = null;
    try {
   
        //将beanName放入正在创建的列表中
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
   
        //将beanName从正在创建的列表中移除
        afterPrototypeCreation(beanName);
    }

}

Spring如何解决循环依赖的问题

Spring创建bean主要的几个步骤:

步骤1:实例化bean,即调用构造器创建bean实例
步骤2:填充属性,注入依赖的bean,比如通过set方式、@Autowired注解的方式注入依赖的bean
步骤3:bean的初始化,比如调用init方法等。

从上面3个步骤中可以看出,注入依赖的对象,有2种情况:

  • 通过步骤1中构造器的方式注入依赖
  • 通过步骤2注入依赖
    先来看构造器的方式注入依赖的bean,下面两个bean循环依赖
@Component
public class ServiceA {
   
    private ServiceB serviceB;
    public ServiceA(ServiceB serviceB) {
   
        this.serviceB = serviceB;
    }
}
@Component
public class ServiceB {
   
    private ServiceA serviceA;
    public ServiceB(ServiceA serviceA) {
   
        this.serviceA = serviceA;
    }
}

构造器的情况比较容易理解,实例化ServiceA的时候,需要有serviceB,而实例化ServiceB的时候需要有serviceA,构造器循环依赖是无法解决的,大家可以尝试一下使用编码的方式创建上面2个对象,是无法创建成功的!

再来看看非构造器的方式注入相互依赖的bean,以set方式注入为例,下面是2个单例的bean:serviceA和serviceB:

@Component
public class ServiceA {
   
    private ServiceB serviceB;
    @Autowired
    public void setServiceB(ServiceB serviceB) {
   
        this.serviceB = serviceB;
    }
}
@Component
public 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值