• [spring] 源码简析 如何解决循环依赖?


    spring是创建实例的时候,是如何解决循环依赖的呢?
    先来看一下isSingleton的实例getBean的整个流程:

    步骤一

    sharedInstance = getSingleton(name)

    1. 来获取缓存的单例实例
      (来源两处,参见图中同色系框框,
      一、单例创建完了会缓存一份singletonObjects; 
      二、创建过程中会缓存一份singletonFactories,创建完了删除)

    2. 如果能够获取得到,则直接返回bean

    3. 如果获取不到,则走getSingleton来实例化单例(参见步骤二)

    步骤二

    getSingleton(name)

    1. 将自身加singletonsCurrentlyInCreation(正在创建的单例容器)中

    2. 执行createBean方法(步骤三)

    3. 将自身从singletonsCurrentlyInCreation(正在创建的单例容器)中移除

    4. 创建的单例实例加入到单例缓存singletonObjects中

    步骤三

    createBean方法

    1. 通过构造函数创建实例

    2. 如果是单例 & 允许循环依赖&

      该bean在singletonsCurrentlyInCreation(正在创建的单例容器)中,则将上述创建的实例缓存到singletonFactories

    3. populatBean依赖注入属性,如果属性是beanName,则调用getBean回到开头

    假设spring没有去解决循环依赖的问题,假设新建如下两个类:

     1@Component
     2public class A {
     3
     4    @Autowired
     5    private B b;
     6
     7
     8    public A() {
     9        System.out.println("A Constructor");
    10    }
    11
    12    @Override
    13    public String toString() {
    14        return "A{}";
    15    }
    16}
     1@Component
     2public class B {
     3
     4    @Autowired
     5    private A a;
     6
     7
     8    public B() {
     9        System.out.println("B Constructor");
    10    }
    11
    12
    13    @Override
    14    public String toString() {
    15        return "B{}";
    16    }
    17}

    那么,在创建A的单例的过程中,需要依赖注入B,转而去创建B,B的创建过程中又要依赖注入A,此时A在beanFactory中不存在,转而又去创建A,这样会形成一种死循环。
    问题的解决办法,就是要在创建过程中,有一条分支路线能够终止创建过程并且返回对象。

    spring是怎么解决循环依赖的呢?
    在创建一个单例的过程中,一旦通过构造函数创建了一个实例,就将中间过程的实例对象暂时缓存起来。
    --> 创建A① 
    --> 执行到步骤三的第2步时,会将刚刚通过构造函数新建的实例缓存起来
    --> 执行步骤三的第3步,依赖注入B,去创建B 
    --> B又依赖注入A,创建A 
    --> 步骤一中能直接从缓存singletonFactories获取到对象 return a
    --> invoke b.setA(a) 
    --> return B 
    --> invoke a.setB(b) 
    --> return A

    以上

    更多源码分析,关注公众号

  • 相关阅读:
    Difference between Nested & Correlated Subqueries
    Oracle Btree、位图、全文索引三大索引性能比较及优缺点汇总(转载)
    subquery unnesting、Subquery unnesting and View Merge
    MySQL中如何定义外键[转]
    索引1
    创建索引和索引类型
    UpdatePanel的用法详解
    索引2
    [HTTP]GET 和POST的区别
    [转]解决silverlight引用中文字体的问题
  • 原文地址:https://www.cnblogs.com/mianteno/p/10692633.html
Copyright © 2020-2023  润新知