spring--解决循环依赖


    首先看下spring建立一个bean的简单流程,假如beanA引用beanB,beanB引用beanA,spring在初始化beanA的时候会形成循环依赖(这里讲的是单例,spring底层只对单例循环依赖进行解决)。

       在记录以前我写了两个测试类进还原循环依赖,一个是ClassA,里面的引用了ClassB,同时ClassB也引用了ClassA。这样子ClassA和ClassB造成了循环依赖。



         spring容器底层在建立ClassB Bean会调用getSingleton先去从一级缓存singletonObjects中拿,若是一级缓存没有,则去二级缓存earlySingletonObjects中拿,二级缓存中没有,则去三级缓存singletonFactories中拿,若是都没有,则调用createBean方法开始建立这个ClassB这个Bean。

       在调用 createbean以前spring会调用isPrototypeCurrentlyInCreation方法来判断当前这个bean存在正在建立中的缓存中(prototypesCurrentlyInCreation),若是不是则放入该缓存中,用于后面循环依赖的解决。由于ClassB是第一次被spring容器加载,因此确定是空,这时候被放入正在建立中的缓存中。

        接着createbean会调用doCreateBean方法,这个真正执行建立bean的方法。该方法调用createBeanInstance(beanName, mbd, args)经过后置处理器判断调用ClassB的构造方法并建立返回ClassB的实例对象,此时对象的ClassA的引用确定是空,由于ClassB的默认构造方法,并无对ClassA赋值。接着spring会将这个早期对象放入三级缓存singletonFactories中。

      放入三级缓存singletonFactories结束后,调用populateBean方法进行属性赋值。populateBean中会去判断ClassB这个Bean有哪些属性以及属性的类型并选择调用哪一个方法来进行赋值,若是是引用类型则调用resolveReference方法进行属性赋值。

       进入resolveReference方法,spring会先去判断当前容器是否有父容器,若是有则从父容器中获取引用对象ClassA,若是没有则从当前容器中获取引用对象ClassA。(spring容许子容器使用父容器的bean,就是在这里体现出来,好比springmvc)这时候程序会调用this.beanFactory.getBean(resolvedName)。从容器中再次获取ClassA这个引用对象。此时getBean会调用doGetBean重新走刚才建立ClassB对象流程。



      一样spring在建立ClassB的引用对象ClassA时,也会去解析ClassA的引用对象。此时ClassA的引用对象是ClassB(此时ClassB对象是暴露在三级缓存中的),这是时候通用调用当前容器的getBean--->doGetBean,在doGetBean中调用getSingleton(beanName)方法。在这里咱们会看到spring在从二级或三级缓存中获取对象是有条件的,条件即便这个对象正在建立中。经过isSingletonCurrentlyInCreation(beanName)这个方法去判断的。

       确实刚建立ClassB的时候记录了ClassB正在建立中,这时候从一级缓存中获取(确定没有由于ClassB还没彻底实例化完),接着继续从二级缓存中获取也没有(因从刚才分析下来,ClassB只单单暴露在三级缓存中),这时候调用singletonObject = singletonFactory.getObject()这个方法,从三级缓存中拿到了早期对象。singletonFactory.getObject()会进一步调用getObject()方法中的getEarlyBeanReference,这里面调用了spring的后置处理器,给开发者对早期对象可以进行提早的修改。好比ClassB 对象里有String str="";能够提早对str进行操做。因此为何spring有二级缓存就能够解决循环依赖。还要用到三级缓存。spring在三级缓存给开发提供了给早期对象扩展的功能。此时将扩展完的早期对象ClassB放入二级缓存,移除三级缓存,并将这个对象返回出去。

      此时ClassA对象ClassB的引用已经拿到值了,因此建立一直往下走,走到addSingleton(beanName, singletonObject)这个方法,将ClassA放入一级缓存singletonObjects,从二级缓存和三级缓存中移除。由于ClassA的bean已经建立完成了,二级缓存和三级缓存已经没用了。此时完整的ClassA的bean返回出去,ClassB的属性ClassA也获得了赋值,ClassB的bean能够继续建立了。

     注意:spring在经过构造器给属性赋值是没法解决循环依赖的,从上面分析来看spring执行createBeanInstance方法去判断调用当前bean的构造方法,此时还未放入三级缓存中。若是是bean做用域是原型也是没法解决循环依赖,由于原型对象并无放在缓存中。

spring