美文网首页
如何解决Spring循环依赖问题

如何解决Spring循环依赖问题

作者: 晏子小七 | 来源:发表于2021-03-09 18:06 被阅读0次

    何为循环依赖?

    循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如图:

    循环依赖

    如何解决?

    ① 主bean通过属性或者setter方法注入所依赖的bean,不是通过构造函数注入

    ② 通过三级缓存实现:singletonObjects,earlySingletonObjects和singletonFactories;

    通过spring-beans包下的DefaultSingletonBeanRegistry类完成

    //一级缓存singletonObject,一级缓存需要用JUC
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    //三级缓存singletonFactory,在synchronized中执行无需考虑线程安全
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    //二级缓存earlySingletonObjects,在synchronized中执行无需考虑线程安全
    private final Map<String, Object> earlySingletonObjects = new HashMap(16);
    
    

    主要是类中的getSingleton方法完成,我们看下getSingleton方法源码实现:

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        //通过beanName获取一级缓存对象
        Object singletonObject = this.singletonObjects.get(beanName);
        //当前对象不在这个单例中 && bean正在创建中
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {
                //获取二级缓存对象earlySingletonObjects
                singletonObject = this.earlySingletonObjects.get(beanName);
                //二级缓存对象不在此单例中而且允许创建
                if (singletonObject == null && allowEarlyReference) {
                    //三级缓存对象创建
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        //三级缓存对象创建成功并放入二级缓存中
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        //移除一级缓存
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
    
        return singletonObject;
    }
    
    

    实现过程是这样的,创建主bean时通过getSingleton将主bean放入上述的isSingletonCurrentlyInCreation列表中,从而使上面的方法实现二三级缓存。

    DefaultSingletonBeanRegistry类中还有一个public的getSingleton方法

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory){
    
        synchronized(this.singletonObjects) {
            //获取一级缓存
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //...部分判断省略
                //将当前beanName放入singletonsCurrentlyInCreation中,以便解决循环依赖问题
                this.beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = this.suppressedExceptions == null;
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet();
                }
    
                try {
                    //直接获取三级缓存中的对象
                    //getObject方法会调用AbstractAutowireCapableBeanFactory的createBean方法
                    singletonObject = singletonFactory.getObject();
                    newSingleton = true;
                } catch ...省略部分代码
            }
    
            return singletonObject;
        }
    }
    
    

    看下createBean方法,本质是调用AbstractAutowireCapableBeanFactory的doCreateBean方法:

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
        // 省略其他代码
    
        // 1\. 调用构造函数创建该bean对象,若不存在构造函数注入,顺利通过
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    
        // 2\. 在singletonFactories缓存中,放入该bean对象,以便解决循环依赖问题
        addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    
        // 3\. populateBean方法:bean对象的属性赋值
        populateBean(beanName, mbd, instanceWrapper);
    
        // 省略其他代码
    }
    
    

    注意<u style="box-sizing: border-box;">addSingleton</u>方法,最后,都会将单例bean对象放入一级缓存singletonObjects中,并移除存放提前曝光对象的二级缓存earlySingletonObjects和该bean对象的创建工厂缓存earlySingletonObjects,解决循坏依赖的问题

    相关文章

      网友评论

          本文标题:如何解决Spring循环依赖问题

          本文链接:https://www.haomeiwen.com/subject/srybqltx.html