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作用域是原型也是无法解决循环依赖,因为原型对象并没有放在缓存中。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值