Spring__循环依赖解读

什么是循环依赖

A类的创建依赖与B类,B类的创建依赖于A类
Spring__循环依赖解读

有4种简单的情况

依赖情况 依赖注入方式 循环依赖是否被解决
AB相互依赖(循环依赖) 均采用setter方法注入
AB相互依赖(循环依赖) 均采用构造器注入
AB相互依赖(循环依赖) A中注入B的方式为setter方法,B中注入A的方式为构造器
AB相互依赖(循环依赖) B中注入A的方式为setter方法,A中注入B的方式为构造器

以上情况后续会讲

Spring怎么去解决循环依赖

三级缓存
在介绍循环依赖之前,先介绍几个集合

Map 作用
三级缓存singletonFactories 保存要创建Bean的Factory
二级缓存earlySingletonObjects 保存根据Bean的Factory创建出来的Bean代理对象
一级缓存singletonObjects 保存创建好的Bean
registeredSingletons 表明集合中的Bean被注册
singletonsCurrentlyInCreation 表明集合种的Bean正在被创建

Bean的循环依赖与Bean的创建密不可分,请先了解Bean的生命周期

  • doGetBean
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

Object sharedInstance = this.getSingleton(beanName);
-----
sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });

在doGetBean中,这两个点是和循环依赖紧密相关的
先看getSingletonString beanName, boolean allowEarlyReference)源码,在上文说的A和B的循环依赖过程中该方法会执行3次;一次是创建A时,因为A也是第一次创建,所以返回为空,不会执行具体流程,当A的生命周期走到属性注入,即org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean,并且要注入B,这时会去创建B,然后创建B的时候再执行一遍,因为B也是第一次创建,所以返回为空,当B进行属性注入,并且要注入A时,又会调用一次该方法,同时因为A已经在被创建,并且A的工厂已经加入到singletonFactories中所以在该方法执行结束后会返回A的代理对象,用于创建B的Bean,那么A的工厂又是在什么时候添加到singletonFactories中的呢?请接下来看org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory

 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 //判断单例池中是否存在已经创建好的Bean
        Object singletonObject = this.singletonObjects.get(beanName);
        //不存在并且该Bean正在被创建
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
        //判断二级缓存中是否存在该Bean的代理
            singletonObject = this.earlySingletonObjects.get(beanName);
            //不存在并且该Bean允许循环依赖
            if (singletonObject == null && allowEarlyReference) {
            //对一级缓存加锁,防止重复创建Bean
                synchronized(this.singletonObjects) {
                //再次判断一级缓存中是否存在创建好的Bean
                    singletonObject = this.singletonObjects.get(beanName);
                    //不存在
                    if (singletonObject == null) {
                    //再次判断二级缓存中是否存在该Bena的代理对象
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        //不存在
                        if (singletonObject == null) {
                        //再次判断三级缓存中是否存在该Bena的工厂
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            //存在
                            if (singletonFactory != null) {
                            //获取到对应的工厂
                                singletonObject = singletonFactory.getObject();
                                //使用该Bean的工厂创建出Bean的代理对象放入二级缓存
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                //移除三级缓存中的Bean工厂
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }

        return singletonObject;
    }

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory
该方法是在进行属性注入之前执行的
源码

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        //对一级缓存加锁
        synchronized(this.singletonObjects) {
        //如果一级缓存是不存在该Bean
            if (!this.singletonObjects.containsKey(beanName)) {
            //将该Bean的factoru加入三级缓存
                this.singletonFactories.put(beanName, singletonFactory);
                //将该Bean对应的代理移出二级缓存
                this.earlySingletonObjects.remove(beanName);
                //将该Bean进行注册
                this.registeredSingletons.add(beanName);
            }

        }
    }

然后看一下另一个getSingleton方法org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
该方法是在doGetBean时触发的,用于获取单例Bean,在这可以想一想,获取不到该Bean会怎么处理?获取不到当然就创建了,在该方法中会对creatBean进行调用

if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                        //调用CreatBean创建Bean
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
在creatBean中会先对要创建的Bean进行校验,校验完成后调用doCreatBean开始创建Bean

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    ......
     try {
            beanInstance = this.doCreateBean(beanName, mbdToUse, args);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
	......
	}

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
也就是在该方法中,完成了Bean的实例化,属性注入,初始化
循环依赖也就是在属性填充的时候被触发的,如果触发了循环依赖,则会创建需要循环依赖的对象,如果该对象正在被创建并且加入到了三级缓存(上文提到过),则会通过三级缓存创建出一个代理对象,用来创建需要的创建的对象。当对象被创建完成后会加入到一级缓存中,然后交给需要被创建的对象去创建。(当AB存在循环依赖,A先被创建,在属性注入时去创建了B,又开始创建B,对B进行属性注入时,发现依赖A,又去获取A,发现A正在被创建,并且已经存在于三级缓存中,就创建A的代理对象交给B,让B进行创建,创建完成后放入一级缓存,然后返回去创建A,A去一级缓存拿到B,再将A创建完成…就是这样子)。

    protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
	......
	 if (instanceWrapper == null) {
	 //实例化
            instanceWrapper = this.createBeanInstance(beanName, mbd, args);
        }
	......
	try {
	//属性填充
            this.populateBean(beanName, mbd, instanceWrapper);
            //初始化
            exposedObject = this.initializeBean(beanName, exposedObject, mbd);
        }
	......
	}

上面说了创建好的Bena要加入到一级缓存,那么是在哪里加入的呢?还记不记得我们是在哪里调用的creatBean了?是在
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)这里对吧!在这里创建肯定也是在这个方法里执行添加的啊!看这个方法的源码会发现,在该方法中存在这样一个方法org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton
来看下源码,可以看出来加入到了一级缓存中了,也就是我们常说的单例池!

 protected void addSingleton(String beanName, Object singletonObject) {
        synchronized(this.singletonObjects) {
        //添加到一级缓存
            this.singletonObjects.put(beanName, singletonObject);
            //移除三级缓存
            this.singletonFactories.remove(beanName);
            //移除三级缓存
            this.earlySingletonObjects.remove(beanName);
            //进行注册 
            this.registeredSingletons.add(beanName);
        }
    }

循环依赖就这样被解决的
Spring__循环依赖解读
不知道大家感觉到没,Spring的循环依赖是在进行属性注入的时候才会触发进行解决,也就是在进行setter时,并不存在使用构造方法时的循环依赖处理,在自己尝试时发现,依据构造方法注入的循环依赖是无法被解决的,也就是最开始的循环依赖解决的表,我把它复制过来了,但是第三种却是可以成功的,第4中却不行,下面说下我自己的理解,如果不对请及时告知!

依赖情况 依赖注入方式 循环依赖是否被解决
AB相互依赖(循环依赖) 均采用setter方法注入
AB相互依赖(循环依赖) 均采用构造器注入
AB相互依赖(循环依赖) A中注入B的方式为setter方法,B中注入A的方式为构造器
AB相互依赖(循环依赖) B中注入A的方式为setter方法,A中注入B的方式为构造器

在说之前,我们要知道一个点,就是Spring在创建Bean的时候是有顺序的,会按照首字母或者一定的方式进行排序,大家可以查一下,在这里就可以得出,A会在B之前被创建。
第三种情况下,A的生命周期会走到属性注入,发现需要注入B,就会去创建B,在创建B的过程中发现需要注入A,又因为A已经进行了实例化,所以B可以使用A实例化后的对象进行创建,也就解决了循环依赖的问题。
Spring__循环依赖解读
第四种情况下:在A进行实例化时就需要用到B,所以会直接去创建B,这时并没有将A实例化完成,没有加入到缓存,以致于在创建B的时候又要回来重新开始创建A,创建A时又要创建B,就这样来回循环。。。就解决不掉了。。。
Spring__循环依赖解读

然后对面试常问的几个问题进行下说明

  1. 用二级缓存能解决循环依赖吗??
    答案是可以的,下面看下分别去掉三级缓存和二级缓存对循环依赖有什么影响
    先去掉三级缓存,在三级缓存中存的是用来创建Bena的工厂,去过去掉了,每次将直接创建代理对象放入二级缓存中,,这样也能处理循环依赖,但是会有什么影响?对比去掉前和去掉后会发现,去掉后会在实例化阶段执行后置处理器,进行对象的代理,而这有背与Spring的设计,会对之后的扩展造成影响,而有了三级缓存之后,就可以在真正需要的时候进行代理,相当于延迟了实例化。
    再看看去掉二级缓存,二及缓存是用来存放代理对象的,而去掉二级缓存后,代理对象会放到哪里去?大概率会是一级缓存中,这样再一级缓存中可能就会存放不同时期的Bean形式,代理和完全的Bean,假如A和B都依赖于C,在创建A的时候,会依赖于C的代理创建出来A,然后一级缓存中的C执行完生命周期将会变成完整的Bean,这是B再创建,B就会根据一级缓存中的C的Bean来创建Bean,这样就会导致,A和B依赖了不同形式的C。
  2. 三级缓存会提高效率吗?
    可以回答影响不大
    如果使用三级缓存并且存在缓存依赖的情况下,对于效率的影响主要是在于对AOP的处理上
    如果使用三级缓存,对于有无AOP的情况,只是进行AOP代理的时机不同,存在循环依赖时,会在处理二级缓存时进行代理,不存在的化则会在初始化时进行代理;
    如果使用二级缓存,同样是需要代理,同样也是代理的时机不同而已
    对于以上的情况来说,对于效率的影响可以说是没有。
上一篇:Spring处理循环依赖只使用二级缓存可以吗?


下一篇:[转帖]"微信支付"勒索病毒制造者被锁定 传播、危害和疫情终极解密 --- 可以学习下一年火绒团队的分析原理的精神.