Spring 是如何解决循环依赖的

首先我们要了解spring 实例化bean的三步骤:
1) doCreateBeanInstance,通过无参构造方法创建一个bean的实例。
2) populateBean,填充bean的属性。
3) initialBean, 执行bean的初始化。
Spring的循环依赖主要发生在第一步和第二步。

Spring的依赖注入有三种情况:

1. 构造器注入,对于构造器注入形式的循环依赖, Spring框架无法自己解决。
2. 对于prototype 作用域类型的bean,形成的循环依赖,Spring框架也无法解决,因为Spring框架对prototype作用域的bean是不缓存的,无法提前暴露一个创建中的bean解决。
3. 对于setter形式的注入,形成的循环依赖,Spring框架是通过三级缓存解决的。
1) 一级缓存, singletonObjects。
2) 二级缓存, earlySingletonObjects。
3) 三级缓存,singletonFactories, 类型为ObjectFactory。

    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
 
    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

看一下getSingleton源码:

    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;
    }

通过ObjectFactory将被依赖的bean提前暴露出去,那么在用三级缓存的时候可以直接get出来。

posted @ 2023-10-05 22:25  wyl010926  阅读(65)  评论(0)    收藏  举报