Springboot Bean循环依赖问题

参考博客原文地址:
https://www.jb51.net/article/168398.htm
https://www.cnblogs.com/mianteno/p/10692633.html
http://www.pianshen.com/article/4112200143/


1.构造器依赖循环

代码示例:

@Component
public class A {
    private B b;
    @Autowired
    public A(B b) {
        this.b=b;
    }
}
@Component
public class B {
    private C c;
    @Autowired
    public B(C c) {
        this.c = c;
    }
}
@Component
public class C {
    private A a;
    @Autowired
    public C(A a) {
        this.a=a;
    }
}

启动运行后运行结果:

可以看到异常的信息:

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

这种循环依赖没有什么解决办法,因为JVM虚拟机在对类进行实例化的时候,需先实例化构造器的参数,而由于循环引用这个参数无法提前实例化,故只能抛出错误。


2.属性注入依赖循环

代码示例:

@Component
public class A {
    @Autowired
    private B b;
    public A() {
        System.err.println(b);
    }
}
@Component
public class B {
    @Autowired
    private C c;
    public B() {
        System.err.println(c);
    }
}
@Component
public class C {
    @Autowired
    private A a;
    public C() {
        System.err.println(a);
    }
}

启动运行后运行结果:

//程序正常启动,输出如下
null
null
null

结论:
Spring通过将实例化后的对象提前暴露给Spring容器中的singletonFactories,解决了循环依赖的问题


3.源码分析 构造器循环依赖异常步骤及原因:

创建一个Bean的过程是:实例化->初始化(属性)->放到缓存中,如下图

这张图是核心

getSingleton源码:

//首次创建的beanName放入singletonsCurrentlyInCreation中
protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

构造器循环依赖,在初始化C时,需要先实例化A,但是A已经在singletonsCurrentlyInCreation有预实例化的记录了,所以此处抛出异常。

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

源码分析 Spring如何解决属性注入 依赖循环问题:

//相关类
org.springframework.beans.factory.support.DefaultListableBeanFactory
org.springframework.beans.factory.support.AbstractBeanFactory
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

可以看到,在实例化后,Bean被添加到singletonFactories中了,所以可以获取到Bean实例,解决了属性循环依赖问题

try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}

4.最终总结:

构造器循环依赖:没有什么解决办法,因为JVM虚拟机在对类进行实例化的时候,需先实例化构造器的参数,而由于循环引用这个参数无法提前实例化,故只能抛出错误。
属性循环依赖:Spring通过将实例化后的对象提前暴露给Spring容器中的singletonFactories,解决了循环依赖的问题

作者:往霄龙
求其上者得其中,求其中者得其下
原文地址:https://www.cnblogs.com/JQKA/p/11864777.html