7、Spirng之循环引用

前言

在讲解本片文章开始之前,必须要先学会上一篇文章创建对象的整体流程,否则这篇文章会学习的很吃力的。

什么是循环引用?

这个很好理解,多个bean之间相互依赖,形成了一个闭环。

比如:A依赖于B、B依赖于A。

public class A{
    B b;
}
public class B{
    A a;
}

引出循环引用 

创建对象的两个步骤:

  1. 获取
  2. 创建

引出关于循环引用的疑问

在创建对象流程的基础上,分析 A依赖于B、B依赖于A,这种情况创建对象的流程。

  1. 获取A对象:getBean("A");
    1. 到单例池中获取A对象:getSingleton("A"),此时单例池中肯定是没有A对象的,所以需要创建A对象。
    2. 创建A对象:doCreateBean("A")。
      1. 实例化A对象:createBeanInstance("A"),此时的A并不是一个完整的A,此时属性并没有被填充,接下来需要对A进行属性填充。
      2. 填充A对象的属性:populateBean("A"),而填充属性的过程中,因为A依赖B,所以在这一步就会去创建B对象
        1. 获取B对象:getBean("B");
          1. 到单例池中获取B对象:getSingleton("B"),此时单例池中肯定是没有B对象的,所以需要创建B对象。
          2. 创建B对象:doCreateBean("B")。
            1. 实例化B对象:createBeanInstance("B"),此时的B并不是一个完整的B,此时属性并没有被填充,接下来需要对B进行属性填充。
            2. 填充B对象的属性:populateBean("B"),而填充属性的过程中,因为B依赖A,因为前面的操作,A并没有被创建完,所以此时也肯定获取不到A对象,那么又该去创建A了,这时候就出现了套娃的情况。

这时候,就出现了如同套娃一样的循环引用的问题,那么接下来就开始讲解怎么解决这种问题吧。

解决循环引用的前提:

两个对象都是单实例的情况下,且通过set方式进行注入才能成功。

三个缓存对象的地方

单例池:singletonObjects

//这个map是缓存所有创建好的对象的地方,也就是经过了整个创建周期的对象(实例化、属性填充、初始化)
//DefaultSingletonBeanRegistry类里面的属性。
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

早期单例池:earlySingletonObjects

//这个map是缓存还没有创建好的对象,并且是需要提前暴漏出来的对象。
//DefaultSingletonBeanRegistry 类里面的属性。
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

单例工厂池:singletonFactories

//这个map是缓存还没有创建好的对象,这里存储的是
//DefaultSingletonBeanRegistry 类里面的属性。
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环引用流程分析

第一步:尝试获取对象A

方法坐标:

getBean() #doGetBean()#getSingleton(String beanName, boolean allowEarlyReference) 

方法源码:

//此时参数 allowEarlyReference=true
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从单例池中获取:没有
   Object singletonObject = this.singletonObjects.get(beanName);
   //判断A是否正在创建:没有正在创建,直接返回null
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

第二步:标记A正在创建

方法坐标

getBean() #doGetBean()#getSingleton(String beanName, ObjectFactory<?> singletonFactory) #beforeSingletonCreation()

方法源码:

protected void beforeSingletonCreation(String beanName) {
   //this.singletonsCurrentlyInCreation.add(beanName) 将A放到正在创建的set中
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

第三步:创建对象A的实例

方法坐标:

getBean() #doGetBean()#getSingleton() #createBean()#doCreateBean()

截取方法部分源码:

//先执行实例化对象的方法
instanceWrapper = createBeanInstance(beanName, mbd, args);

//this.allowCircularReferences=true
//isSingletonCurrentlyInCreation =true  这个为true就是在上一步设置的。
//所以这个整体为 true
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isTraceEnabled()) {
      logger.trace("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
   }
   //将A放到singletonFactories(单例工厂池)中,key是A的id,value是创建A对象的一个lambda表达式,
   //如果A对象没有做代理,那么这个lambda表达式返回的就是A对象本身
   //如果A对象做了代理,那么这个lambda表达式返回的就是A的代理对象
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

第四步:A对象进行属性填充,填充B对象

方法坐标:

getBean() #doGetBean()#getSingleton() #createBean()#doCreateBean()#populateBean()#applyPropertyValues()

截取方法部分源码:

//applyPropertyValues()这个方法里面有如下这一行代码:
//这行代码主要工作是做转换用的:
//如果是TypedStringValue类型:将TypeStringValue转换成 "1"
//如果是 RuntimeBeanReference类型:从工厂中获得B对象,
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);


//上面那行代码的resolveValueIfNecessary()方法里面有如下代码:
//因为B对象是RuntimeBeanReference类型的,所以执行if块中的resolveReference()方法
if (value instanceof RuntimeBeanReference) {
   RuntimeBeanReference ref = (RuntimeBeanReference) value;
   return resolveReference(argName, ref);
}


//上面那行代码的resolveReference()方法里面有如下代码:
//resolvedName就是B对象的id,
//当发现B依赖了A,所以会通过这行代码进行getBean("B")的操作,然后又会执行接下来的步骤:
//1.尝试获取B对象
//2.标记B正在创建。
//3.创建B对象的实例
//4.B对象进行属性填充,填充B属性的时候,会发现B又依赖了A,所以会通过这行代码再次进行getBean("A")的操作,注意,再次获取A时发生了变化,咱们往下接着看
this.beanFactory.getBean(resolvedName);

第五步:再次获取对象A(在填充对象B属性时)

方法坐标:

getBean() #doGetBean()#getSingleton(String beanName, boolean allowEarlyReference) 

方法源码:

//此时参数 allowEarlyReference=true
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从单例池中获取:没有
   Object singletonObject = this.singletonObjects.get(beanName);
   //判断A是否正在创建:A正在创建中
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      //从早期单例池获取A对象:没有
      singletonObject = this.earlySingletonObjects.get(beanName);
      //if块为true
      if (singletonObject == null && allowEarlyReference) {
         //锁住单例池,防止并发,做个安全保险
         synchronized (this.singletonObjects) {
            //再次从单例池中获取A对象,做个安全保险:获取不到
            singletonObject = this.singletonObjects.get(beanName);
            //if块为true
            if (singletonObject == null) {
               //再次从早期单例池获取A对象:没有
               singletonObject = this.earlySingletonObjects.get(beanName);
               //if块为true
               if (singletonObject == null) {
                  //从单例工厂池获取A对象:能获取到
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  //if块为true
                  if (singletonFactory != null) {
                     //调用单例工厂池存储的lambda表达式,获取A对象
                     //注意:A对象如果做了代理,此处获取的就是A的代理对象,如果A没有做代理,那么此处获取的就是A对象本身。
                     singletonObject = singletonFactory.getObject();
                     //将A放入早期单例池,将这个不完整的对象提前暴漏出来,因为对象的引用一般都是对象的地址值,所以提前将对象暴漏出来,后期再赋值就可以了。
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     //将A从单例工厂池移除
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

第六步:实例化B对象

在第五步能获取到提前暴漏出来的A对象,直接返回给B,此时B正处在属性填充阶段

方法坐标:

getBean() #doGetBean()#getSingleton() #createBean()#doCreateBean()#initializeBean()

截取方法部分源码:

exposedObject = initializeBean(beanName, exposedObject, mbd);

第七步:更新B对象存储的位置

方法坐标:

getBean() #doGetBean()#getSingleton(lambda)
  1. 截取方法部分源码:
    finally {
       if (recordSuppressedExceptions) {
          this.suppressedExceptions = null;
       }
       afterSingletonCreation(beanName);
    }
    
    //上面finally块afterSingletonCreation()方法内部实现如下:
    //判断B是否是被排除的Bean,同时将B从正在创建列表(singletonsCurrentlyInCreation)中移除。
    protected void afterSingletonCreation(String beanName) {
       if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
          throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
       }
    }
  2. 截取方法部分源码:
    if (newSingleton) {
       addSingleton(beanName, singletonObject);
    }
    
    //上面if块addSingleton()方法内部实现如下:
    protected void addSingleton(String beanName, Object singletonObject) {
       synchronized (this.singletonObjects) {
          //将B对象放入单例池中
          this.singletonObjects.put(beanName, singletonObject);
          //将B对象从单例工厂池中移除
          this.singletonFactories.remove(beanName);
          //将B对象从早期单例池中移除
          this.earlySingletonObjects.remove(beanName);
          //将B对象添加到已经注册过的set集合中。
          this.registeredSingletons.add(beanName);
       }
    }

        

第八步:实例化A对象,更新A的存储位置

具体代码参考实例化B对象,更新B的存储位置

总结

这篇文章细品,那么在此给大家留个问题:

单例工厂池(singletonFactories)存储的是创建对象的lambda表达式,那么不考虑循环引用的问题,如果只创建一个对象A,并且A对象不会涉及循环引用,A对象是在哪里调用的singletonFactories的getObject()方法获取的A对象。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值