Spring中解决循环引用

目录

 

一、前言    

二、源码分析

1.getBean(String name)方法

2.getSingleton(beanName)方法

3.getSingleton(String beanName, ObjectFactory singletonFactory)方法

4.createBean(beanName, mbd, args)方法

5. addSingletonFactory(beanName,  singletonFactory) 方法

6.addSingleton(beanName, singletonObject)方法

三、总结


一、前言    

    循环引用,简单来说是指A类中依赖B类,B类中又依赖A类,当然这个引用的链也可能更长(A->B->C->....->A);

Spring中对于单例模式的循环引用主要是两种,一种是构造函数的循环引用,一种是set注入的循环引用

构造函数的循环引用无法解决(后边会讲原因),这里主要讲set注入的循环引用,假设目前我们的引用链是A类依赖B类,B类也依赖A类(A->B->A)

 

二、源码分析

    当spring解析注解或配置文件之后,所有的类将会以BeanDefinition的形式保存在容器中,然后对这些BeanDefinition实例化。

实例化用到的方法主要是AbstractBeanFactory. getBean(String name);

1.getBean(String name)方法

调用链
    AbstractBeanFactory.getBean(String name);
    ->AbstractBeanFactory. doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly)
      
      代码如下:
      protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //传入的name可能是alias,也可能有&前缀(工厂类) 得转化一下
       final String beanName = transformedBeanName(name);
       Object bean;
    
       //首先从缓存中获取  这里讲的缓存主要是
       //singletonObjects, earlySingletonObjects  重点
       Object sharedInstance = getSingleton(beanName);
       if (sharedInstance != null && args == null) {
          ....//省略部分代码
          //如果缓存中存在  因为可能得到的事FactoryBean 
          //而我们需要的是FactoryBean.getObject创建的对象 在此作处理
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
       }
    
       else {
           //如果缓存中没有
           ......//省略部分代码
    
          try {
              //我们的类可能继承了父类  将父类的属性合并一下
             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
             checkMergedBeanDefinition(mbd, beanName, args);
    
            //xml配置文件中使用了depend-on属性或者java文件中使用了@DependsOn 依赖的类先实例化
             String[] dependsOn = mbd.getDependsOn();
             if (dependsOn != null) {
                for (String dep : dependsOn) {
                   if (isDependent(beanName, dep)) {
                      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                   }
                   registerDependentBean(dep, beanName);
                   try {
                      getBean(dep);
                   }
                   catch (NoSuchBeanDefinitionException ex) {
                      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                   }
                }
             }
    
             //如果这个BeanDefinition是单例
             if (mbd.isSingleton()) {
                 //创建对象  主要是通过ObjectFactory创建
                 //注意:这里使用lambda表达式 创建了一个匿名内部类工厂
                sharedInstance = getSingleton(beanName, () -> {
                   try {
                      return createBean(beanName, mbd, args);
                   }
                   catch (BeansException ex) {
                      destroySingleton(beanName);
                      throw ex;
                   }
                });
                   //如果缓存中存在  因为可能得到的事FactoryBean 
                  //而我们需要的事FactoryBean.getObject创建的对象 在此作处理
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
             }
    
            ......//省略部分代码
       }
    
    ....//省略部分代码
       return (T) bean;
    }

2.getSingleton(beanName)方法

    首先先看看getSingleton(beanName)从缓存中获取做了些啥。

调用链
DefaultSingletonBeanRegistry.getSingleton(String beanName)
//return getSingleton(beanName, true); //allowEarlyReference是true
->DefaultSingletonBeanRegistry.getSingleton(String beanName, boolean allowEarlyReference)


代码如下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   //从singletonObjects中获取  这是一个Map<String, Object>
   Object singletonObject = this.singletonObjects.get(beanName);
   //singletonsCurrentlyInCreation是一个Set<String>  实例化之后会BeanName加入到集合里 
   //判断singletonsCurrentlyInCreation是否包含beanName,如果包含beanName  表示该beanDefinition已经实例化 但是
   //还没有给属性赋值  (后边会提及)
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
          //从 Map<String, Object> earlySingletonObjects获取
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
             //如果earlySingletonObjects中没有 则获取ObjectFactory得到对象的引用
             //至于ObjectFactory什么时候放入singletonFactories中  后边会提及
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
                //earlySingletonObjects 和 生成这个对象的ObjectFactory是互斥的
                //通过ObjecFactory生成后  就放到earlySingleObjects中,以后无需
                //ObjectFactory再创建了  
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

    对于之前没有实例化过得beanDefinition,这里肯定返回null,如果缓存中没有,那我们需要自己实例化对象。

3.getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法

    接下来我们看DefaultSingleBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)

如下:
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
       Assert.notNull(beanName, "Bean name must not be null");
       synchronized (this.singletonObjects) {
           ......//省略部分代码
           //将beanName加入到singletonsCurrentlyInCreation中
           beforeSingletonCreation(beanName);
            ......//省略部分代码
             try {
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
             }
             catch (IllegalStateException ex) {
             ....
             }
             catch (BeanCreationException ex) {
              ....
             }
             finally {
                if (recordSuppressedExceptions) {
                   this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
             }
             if (newSingleton) {
                addSingleton(beanName, singletonObject);
             }
          }
          return singletonObject;
       }
    }

 

      这里主要是将beanName加入到singletonsCurrentlyInCreation集合中(前面从缓存中取对象时用到过),然后调用ObjectFactory.getObject方法 而通过doGetBean方法里匿名内部类可知,就是调用createBean(beanName, mbd, args)方法。

4.createBean(beanName, mbd, args)方法

代码如下:
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
          ......//省略部分代码
       try {
          Object beanInstance = doCreateBean(beanName, mbdToUse, args);
          if (logger.isTraceEnabled()) {
             logger.trace("Finished creating instance of bean '" + beanName + "'");
          }
          return beanInstance;
       }
       catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        ...
       }
       catch (Throwable ex) {
         ...
    }
    
    调用链:
    ->doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
    
    
    //实例化对象的关键
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

       // Instantiate the bean.
       BeanWrapper instanceWrapper = null;
       if (mbd.isSingleton()) {
          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
       }
       //调用构造函数实例化对象
       //到此对象已经被实例化了,只是依赖的属性还没有被赋值或实例化
       //比如 A类中有个属性B,需要进行注入  此时B是没有注入的
       if (instanceWrapper == null) {
          instanceWrapper = createBeanInstance(beanName, mbd, args);
       }
       final Object bean = instanceWrapper.getWrappedInstance();
       Class<?> beanType = instanceWrapper.getWrappedClass();
       if (beanType != NullBean.class) {
          mbd.resolvedTargetType = beanType;
       }
    
     ......//省略部分代码
    
    
       boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
             isSingletonCurrentlyInCreation(beanName));
       if (earlySingletonExposure) {
           //如果是单例&&允许循环依赖&&对象正在构建中(已经实例化,但是属性没有赋值)
           //isSingletonCurrentlyInCreation就是判断singletonsCurrentlyInCreation
           //中有没有beanName,在前面我们已经将beanName加入到该集合中了
          if (logger.isTraceEnabled()) {
             logger.trace("Eagerly caching bean '" + beanName +
                   "' to allow for resolving potential circular references");
          }
         //将beanName和ObjectFactory放入SingleFactories中
         //ObjectFactory 返回的事这里对象的引用(已经实例化,但是它的属性还没有赋值)
          addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
       }
    
       // Initialize the bean instance.
       Object exposedObject = bean;
       try {
           //给对象的属性赋值
          populateBean(beanName, mbd, instanceWrapper);
          //调用诸如init-method等初始化方法
          exposedObject = initializeBean(beanName, exposedObject, mbd);
       }
       catch (Throwable ex) {
          ...
       }
    
     ......//省略部分代码
       return exposedObject;
    }

 

5. addSingletonFactory(beanName,  singletonFactory) 方法

    这里我们注重看addSingletonFactory方法

 

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      if (!this.singletonObjects.containsKey(beanName)) {
         this.singletonFactories.put(beanName, singletonFactory);
         this.earlySingletonObjects.remove(beanName);
         this.registeredSingletons.add(beanName);
      }
   }
}

     初次实例化singletonObjects肯定不包含该beanName,这里我们将bean,ObjectFactory加入到了singleFactories,以便下次实例化时从缓存获取的时候 就可以通过这个ObjectFactory得到对象的引用了(虽然只是实例化了,属性还没有赋值,但当后边的 populateBean(beanName, mbd, instanceWrapper);执行完之后,属性就赋值完成了)

 

6.addSingleton(beanName, singletonObject)方法

最后我们再看一下Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法中的addSingleton(beanName, singletonObject);

 

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
   }
}

    当对象实例化流程走完之后,将beanName,singleObject放入singletonObjects中,以便其他对象依赖时从缓存中获取的时候进行返回

 

三、总结

spring中解决循环依赖 假设A类依赖B类,B类依赖A类(A->B->A)

那么当A实例化时会从缓存中获取

首先从singleObjects中获取,singleObjcts存放的对象是已经实例化,并且属性也赋值了

如果singleObjects中没有 则从earlySingletonObjects中获取,earlySingleObjects存放的是对象已经实例化,但是属性还没有赋值

如果earlySingleObjects中没有 则使用ObjectFactory获取对象的引用,放入earlySingleObjects中

当然如果A是第一次实例化,从缓存中返回null

这时需要我们自己实例化,首先调用构造函数实例化,然后在属性赋值前将beanName,和返回对象引用的ObjectFactory加入到singleFactories中(这也是构造函数依赖不能解决的原因,因为ObjectFactory加入到singleFactories中是在构造函数实例化之后)

最后进行属性赋值,

因为A依赖B,我们需要实例化B,对B做同样的处理,当B又依赖A时因为我们已经将获取A引用的ObjectFactory放入了singleFactories中,所以这里我们能获取到A的引用

最终将B的beanName,singleObject加入到缓存singleObjects中,向上递归,将A的beanName,siingleObject加入到singleObjects中。

附图:

 

 

 

 

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值