循环依赖问题是指:类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。
例如:A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题。

- @Component
- public class A {
- @Autowire
- private B b;
- }
-
-
- @Component
- public class B {
- @Autowire
- private C c;
- }
-
-
- @Component
- public class C {
- @Autowire
- private A a;
- }
1. 构造器的循环依赖
2. 属性的循环依赖
我们都知道,单例Bean初始化完成,要经历三步:
实例化(Instantiation)→属性赋值(Populate)→初始化(Initialization)
注入就发生在第二步,属性赋值;对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,结合这个过程,Spring为了解决单例的循环依赖问题,使用了三级缓存。
Spring对循环依赖的解决方法可以概括为 用三级缓存方式达到Bean提前曝光的目的
- /** Cache of singleton objects: bean name --> bean instance */
- private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
-
- /** Cache of singleton factories: bean name --> ObjectFactory */
- private final Map<String, ObjectFactory>> singletonFactories = new HashMap<String, ObjectFactory>>(16);
-
- /** Cache of early singleton objects: bean name --> bean instance */
- private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
这三级缓存分别指:
1、一级缓存 : Map
2、二级缓存 : Map
3、三级缓存 : Map
获取单例Bean的源码如下:
- public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
- ...
- @Override
- @Nullable
- public Object getSingleton(String beanName) {
- return getSingleton(beanName, true);
- }
- @Nullable
- protected Object getSingleton(String beanName, boolean allowEarlyReference) {
- Object singletonObject = this.singletonObjects.get(beanName);
- if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
- synchronized (this.singletonObjects) {
- singletonObject = this.earlySingletonObjects.get(beanName);
- if (singletonObject == null && allowEarlyReference) {
- ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
- if (singletonFactory != null) {
- singletonObject = singletonFactory.getObject();
- this.earlySingletonObjects.put(beanName, singletonObject);
- this.singletonFactories.remove(beanName);
- }
- }
- }
- }
- return singletonObject;
- }
- ...
- public boolean isSingletonCurrentlyInCreation(String beanName) {
- return this.singletonsCurrentlyInCreation.contains(beanName);
- }
- protected boolean isActuallyInCreation(String beanName) {
- return isSingletonCurrentlyInCreation(beanName);
- }
- ...
- }
& 拿bean的时候先从一级缓存singletonObjects中获取;
& 如果获取不到或者对象正在创建中,就从二级缓存earlySingletonObjects中获取;
& 如果还是获取不到就从三级缓存singletonFactories中获取,然后将获取到的对象放到二级缓存earlySingletonObjects中,并且将bean对应的三级缓存singletonFactories清除;
& bean初始化完毕,放到一级缓存singletonObjects中,将bean对应的二级缓存earlySingletonObjects清除
知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。
不能;
主要是为了生成代理对象。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。
1. 业务代码中尽量不要使用构造器注入
2. 尽量使用field注入而非setter方法注入