本篇内容介绍了“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会调用doCreateBean方法,这个真正执行创建bean的方法。该方法调用createBeanInstance(beanName, mbd, args)通过后置处理器判断调用ClassB的构造方法并创建返回ClassB的实例对象,此时对象的ClassA的引用肯定是空,因为ClassB的默认构造方法,并没有对ClassA赋值。接着spring会将这个早期对象放入三级缓存singletonFactories中。 进入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)这个方法去判断的。 此时ClassA对象ClassB的引用已经拿到值了,所以创建一直往下走,走到addSingleton(beanName, singletonObject)这个方法,将ClassA放入一级缓存singletonObjects,从二级缓存和三级缓存中移除。因为ClassA的bean已经创建完成了,二级缓存和三级缓存已经没用了。此时完整的ClassA的bean返回出去,ClassB的属性ClassA也得到了赋值,ClassB的bean可以继续创建了。 注意:spring在通过构造器给属性赋值是无法解决循环依赖的,从上面分析来看spring执行createBeanInstance方法去判断调用当前bean的构造方法,此时还未放入三级缓存中。如果是bean作用域是原型也是无法解决循环依赖,因为原型对象并没有放在缓存中。
“spring解决循环依赖的方法”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注天达云网站,小编将为大家输出更多高质量的实用文章!