从Spring源码看Spring如何解决循环引用的问题

2023年 8月 13日 14.5k 0

Spring如何解决循环引用的问题

关于循环引用,首先说一个结论:

Spring能够解决的情况为:两个对象都是单实例、且通过set方法进行注入。

两个对象都是单实例,通过构造方法进行注入,Spring不能进行循环引用问题;

两个对象都是多实例的情况下,不管是set注入,还是构造注入,都不能解决Spring循环引用问题。

循环引用问题介绍

循环引用问题即:

有A,B两个类,A类中有B类型的成员变量b、B类中有A类型的成员变量a。创建a的过程需要b,创建b的过程又需要a;

循环引用问题演示

循环引用问题分析

请看如下流程:

  • 调用getBean("a")来获取a对象;
  • 先调用getSingleton("a")来尝试获取a,但是获取不到;
  • 需要调用doCreateBean()来创建a;
  • a的b属性是null,需要填充b属性;
  • 调用getBean("b")来获取b对象;
  • 先调用getSingleton("b")来尝试获取b,但是获取不到;
  • 需要调用doCreateBean()来创建b;
  • b的a属性是null,需要填充a属性;
  • 又需要要调用getBean("a")来获取a。
  • 这时getBean("a")可以获取到吗?如果能获取到,是在哪里获取的?如果获取不到,又会有什么问题呢?

    我们首先看下getSingleton()源码:

    image-20230809203549677

    addSingleton方法如下图:

    addSingleton

    如此可以看到,在进行实例化、属性填充、初始化都完成后才会放到singletonObjects中。

    那getSingleton()方法就获取不到a,只能再去创建a对象了吗?当然不是,如果再去创建a,a就不是单例的呢。

    所以这就需要**没有创建完全的a也要存储起来。**但是并没有存储到singletonObjects中,因为singletonObjects是存储例化、属性填充、初始化都完成后的对象。

    Spring又为我们定义了两个存储的位置:earlySingletonObjects、singletonFactories。

    那什么时候将未创建完全的对象存储起来呢?

    这我们应该在实例化对象完成后,填充属性前的代码查找。可以看到如下代码:

    doCreateBean

    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

    addSingletonFactory方法源码如下:
    protected void addSingletonFactory(String beanName, ObjectFactory

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论