前言

本文基于springboot版本2.5.1

    <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>2.5.1</version>
        <relativepath/> <!-- lookup parent from repository -->
    </parent>

本文主要聚焦在循环依赖部分,主要用单例bean来进行讲解,其他bean实现的流程不会过多涉及。

1、什么叫循环依赖呢

简单来说就是springboot容器中的多个bean,如a、b两个bean,a有属性b需要注入,b有属性a需要注入,形成相互依赖的情况。

看下代码,就是类似下面这种情况

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;

@component
public class servicea {
    @autowired
    private serviceb serviceb;
}

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;

@component
public class serviceb {
    @autowired
    private servicea servicea;
}

上面有两个bean,分别是servicea,serviceb。servicea中需要注入serviceb的实例,serviceb中需要注入servicea的实例,这就是一种典型的循环依赖,其他还有方法参数循环依赖的场景等等,但是它们的内部实现基本是一样的。

2、具体出现循环依赖的代码逻辑

获取bean的方法

在springboot中默认的beanfactory是defaultlistablebeanfactory,在我们获取bean对象的时候,如果bean对象存在就直接返回,如果不存在,就先创建bean对象再返回。

我们先看下我们获取bean的常用方法都有哪些

public <t> t getbean(class<t> requiredtype) throws beansexception
public object getbean(string name) throws beansexception
public <t> map<string, t> getbeansoftype(@nullable class<t> type) throws beansexception
public map<string, object> getbeanswithannotation(class<? extends annotation> annotationtype)
public void preinstantiatesingletons() throws beansexception 

常用的获取bean的方法主要有上面几个和它们的重载版本,对于第3行、第4行、第5行最终都会调用到第2行的方法来获取bean。而它也会通过调用dogetbean(在abstractbeanfactory这个类中)来获取bean

 public object getbean(string name) throws beansexception {
  return dogetbean(name, null, null, false);
 }

第1行的方法也会调用dogetbean来获取bean

 public <t> t getbean(string name, @nullable class<t> requiredtype, @nullable object... args)
   throws beansexception {

  return dogetbean(name, requiredtype, args, false);
 }

所有最终获取bean的方法都是

 protected <t> t dogetbean(
   string name, @nullable class<t> requiredtype, @nullable object[] args, boolean typecheckonly)
   throws beansexception {

这个方法,这个方法是protected的,是不对外提供的。所以我们不能直接调用它,只能通过上面提供的5个方法来获取bean对象。

下面我们从dogetbean这里来看下servicea创建的过程

 protected <t> t dogetbean(
   string name, @nullable class<t> requiredtype, @nullable object[] args, boolean typecheckonly)
   throws beansexception {
   //如果bean之前存在,这里返回的shareinstance就是非空,就会从后面的if分支中返回,如果bean之前不存在,就会执行后面的bean创建及注入属性的过程
   object sharedinstance = getsingleton(beanname);
   if (sharedinstance != null && args == null) {
   ......
   //如果当前不只是检查,而且是创建bean,这个参数就是false,在这里就会做个bean创建的标记,把beanname 加到alreadycreated里面去
   if (!typecheckonly) {
    markbeanascreated(beanname);
   }
    //我们当前要创建的bean是单例的,就会走到这里去,下面我们走到里面的调用去看看
    // create bean instance.
    if (mbd.issingleton()) {
     sharedinstance = getsingleton(beanname, () -> {
      try {
       return createbean(beanname, mbd, args);
      }
      catch (beansexception ex) {
       // explicitly remove instance from singleton cache: it might have been put there
       // eagerly by the creation process, to allow for circular reference resolution.
       // also remove any beans that received a temporary reference to the bean.
       destroysingleton(beanname);
       throw ex;
      }
     });
     beaninstance = getobjectforbeaninstance(sharedinstance, name, beanname, mbd);
    }

  }

 public object getsingleton(string beanname, objectfactory<?> singletonfactory) {
  assert.notnull(beanname, "bean name must not be null");
  synchronized (this.singletonobjects) {
                ......
                //这里会把当前bean的名字加入到当前正在创建的单例对象集合singletonscurrentlyincreation中
    beforesingletoncreation(beanname);
    ......
    try {
                    //这里就是调用上面的return createbean(beanname, mbd, args);这个方法,我们进这里面去看看
     singletonobject = singletonfactory.getobject();
     newsingleton = true;
    }
    ......
   }
   return singletonobject;
  }
 }

 @override
 protected object createbean(string beanname, rootbeandefinition mbd, @nullable object[] args)
   throws beancreationexception {
  ......
  // make sure bean class is actually resolved at this point, and
  // clone the bean definition in case of a dynamically resolved class
  // which cannot be stored in the shared merged bean definition.
        //在这里获取要创建的bean的class对象
  class<?> resolvedclass = resolvebeanclass(mbd, beanname);
  ......
  try {
            //调用这里来创建,我们再走到这里面去看看
            //3个参数分别为
            //1、beanname  bean对象的名字
            //2、mbdtouserootbeandefinition对象,可以认为就是bean的元数据信息,包含bean的类对象,bean的类上注解,bean实际位置路径等等
            //3、args  bean对象的构造方法的实参,这里一般是空的
   object beaninstance = docreatebean(beanname, mbdtouse, args);
   if (logger.istraceenabled()) {
    logger.trace("finished creating instance of bean '" + beanname + "'");
   }
   return beaninstance;
  }
  ......
 }

protected object docreatebean(string beanname, rootbeandefinition mbd, @nullable object[] args)
      throws beancreationexception {

   ......
   //真正创建bean对象是在这里,这里返回的instancewrapper是bean对象的类实例的包装对象beanwrapper
   if (instancewrapper == null) {
      instancewrapper = createbeaninstance(beanname, mbd, args);
   }
   //这里的bean就是实际创建的bean对象的类实例
   object bean = instancewrapper.getwrappedinstance();
   class<?> beantype = instancewrapper.getwrappedclass();
   if (beantype != nullbean.class) {
      mbd.resolvedtargettype = beantype;
   }
 ......
   // eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like beanfactoryaware.
   //看上面的注释大概也能明白, 大概意思就是早期的单例缓存,为了解决由 beanfactoryaware等等触发的循环依赖
   //mbd.issingleton()  表示bean是单例的(这个是bean对应的类上的,默认就是单例),
   //this.allowcircularreferences 允许循环引用,这个是beanfactory的成员属性,默认也是true
   //issingletoncurrentlyincreation(beanname) 表示是否在当前正在创建的bean集合中。beforesingletoncreation(beanname);我们在前面执行过这句就加到正在创建的bean集合中了
   //这里earlysingletonexposure 就是true了,会进到if分支中
   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");
      }
      //这句主要是将将() -> getearlybeanreference(beanname, mbd, bean) 这个lambda表达式存储到this.singletonfactories集合中
      addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean));
   }

   // initialize the bean instance.
   object exposedobject = bean;
   try {
      //在这里就会进行属性填充,完成成员注入等等,也就是在这里servicea这个bean会注入serviceb这个成员属性,我们走进这个方法去看看
      populatebean(beanname, mbd, instancewrapper);
      ......
   }
  ......

   return exposedobject;
}

 protected void populatebean(string beanname, rootbeandefinition mbd, @nullable beanwrapper bw) {
  ......
  if (hasinstawarebpps) {
   if (pvs == null) {
    pvs = mbd.getpropertyvalues();
   }
   //真正的属性注入是在这里完成的,aop也是在这里来完成的。这里是获取beanfactory中的instantiationawarebeanpostprocessor对bean对象进行增强
   //如果属性注入用的是@resource,就会用commonannotationbeanpostprocessor来完成
   //如果属性注入用的是@autowired,就会用autowiredannotationbeanpostprocessor来完成
   //如果是aop 就会使用infrastructureadvisorautoproxycreator来生成对应的代理对象
   //我们这里使用的是@autowired,所以会用autowiredannotationbeanpostprocessor来完成注入。我们走到它的postprocessproperties的去看看
   for (instantiationawarebeanpostprocessor bp : getbeanpostprocessorcache().instantiationaware) {
    propertyvalues pvstouse = bp.postprocessproperties(pvs, bw.getwrappedinstance(), beanname);
    ......
 }
 @override
 public propertyvalues postprocessproperties(propertyvalues pvs, object bean, string beanname) {
        //这里主要是获取bean的类属性和方法上的org.springframework.beans.factory.annotation.autowired,org.springframework.beans.factory.annotation.value注解来进行注入
  injectionmetadata metadata = findautowiringmetadata(beanname, bean.getclass(), pvs);
  try {
            //继续进去看看
   metadata.inject(bean, beanname, pvs);
  }
  ......
 }
public void inject(object target, @nullable string beanname, @nullable propertyvalues pvs) throws throwable {
   ......
   //对每一个属性分别进行注入,继续进去
         element.inject(target, beanname, pvs);
      }
   }
}

    @override
    protected void inject(object bean, @nullable string beanname, @nullable propertyvalues pvs) throws throwable {
     field field = (field) this.member;
     object value;
     //如果之前缓存过就从缓存取,我们是第一次注入,所以之前没有缓存,不会走这个分支
     if (this.cached) {
      try {
       value = resolvedcachedargument(beanname, this.cachedfieldvalue);
      }
      catch (nosuchbeandefinitionexception ex) {
       // unexpected removal of target bean for cached argument -> re-resolve
       value = resolvefieldvalue(field, bean, beanname);
      }
     }
     else {
      //会走这里来解析字段的值,再进去
      value = resolvefieldvalue(field, bean, beanname);
     }
     if (value != null) {
      reflectionutils.makeaccessible(field);
      field.set(bean, value);
     }
    }

  @nullable
  private object resolvefieldvalue(field field, object bean, @nullable string beanname) {
   //创建字段的包装类dependencydescriptor
   dependencydescriptor desc = new dependencydescriptor(field, this.required);

   try {
    //调用这里完成对应字段值的查找,再进去
    value = beanfactory.resolvedependency(desc, beanname, autowiredbeannames, typeconverter);
   }
   catch (beansexception ex) {
    throw new unsatisfieddependencyexception(null, beanname, new injectionpoint(field), ex);
   }
   synchronized (this) {
    //获取到值之后,进行缓存
    if (!this.cached) {
      ......
     }
     this.cachedfieldvalue = cachedfieldvalue;
     this.cached = true;
    }
   }
   return value;
  }
 }

 public object resolvedependency(dependencydescriptor descriptor, @nullable string requestingbeanname,
   @nullable set<string> autowiredbeannames, @nullable typeconverter typeconverter) throws beansexception {

  descriptor.initparameternamediscovery(getparameternamediscoverer());
  if (optional.class == descriptor.getdependencytype()) {
   return createoptionaldependency(descriptor, requestingbeanname);
  }
  else if (objectfactory.class == descriptor.getdependencytype() ||
    objectprovider.class == descriptor.getdependencytype()) {
   return new dependencyobjectprovider(descriptor, requestingbeanname);
  }
  else if (javaxinjectproviderclass == descriptor.getdependencytype()) {
   return new jsr330factory().createdependencyprovider(descriptor, requestingbeanname);
  }
  else {
   //当前的类是一个普通的class,会走到这里面,由于我们的bean没有lazy注解,所以这里返回时null,走到下面的if分支
   object result = getautowirecandidateresolver().getlazyresolutionproxyifnecessary(
     descriptor, requestingbeanname);
   if (result == null) {
    //在这里我们看下这里的入参。
    //descriptor是包含了需要注入的字段的信息。
    //requestingbeanname是当前正在创建的bean的名字servicea,
    //autowiredbeannames是当前需要注入的字段的对应的bean的名字的集合,这里只有serviceb
    //typeconverter这个是进行注入时做类型转换的,这里我们可以不用关注这个
    result = doresolvedependency(descriptor, requestingbeanname, autowiredbeannames, typeconverter);
   }
   return result;
  }
 }

 @nullable
 public object doresolvedependency(dependencydescriptor descriptor, @nullable string beanname,
   @nullable set<string> autowiredbeannames, @nullable typeconverter typeconverter) throws beansexception {
   ......
   if (instancecandidate instanceof class) {
    //又会调用到这里,我们再进入到dependencydescriptor的resolvecandidate去看看
                //注意:这里的autowiredbeanname是我们需要注入的属性名这里是serviceb
    instancecandidate = descriptor.resolvecandidate(autowiredbeanname, type, this);
   }
   ......
 }

 public object resolvecandidate(string beanname, class<?> requiredtype, beanfactory beanfactory)
   throws beansexception {
  //看到没,到这里就出现循环调用了,到这里又会重新调用beanfactory.getbean("serviceb")去创建serviceb的bean对象,完成后注入到serivcea对应的bean上的属性上来,这时代码又会从本节开头的位置开始执行,先创建serviceb对象实例,再去注入serviceb对象的servicea属性。
        //最终会执行到beanfactory.getbean("servicea")这里
  return beanfactory.getbean(beanname);
 }

就是下面图的样子

3、解决循环依赖的代码实现

接着上面的beanfactory.getbean(“servicea”)这行代码我们继续往下看

这次又会走到这里

 protected <t> t dogetbean(
   string name, @nullable class<t> requiredtype, @nullable object[] args, boolean typecheckonly)
   throws beansexception {
  //我们第二部分就是从这里开始的,又走回来了,但这次又会有所不同
  string beanname = transformedbeanname(name);
  object beaninstance;

  // eagerly check singleton cache for manually registered singletons.
  //这次我们这里返回的就不是空了,sharedinstance对象的值就是对应servicea的bean对象了,这次就会从if分支中返回,而之前我们不会进这里的if分支而是进入else分支导致后面出现了循环依赖的问题,这次我们进到这个方法看看
  object sharedinstance = getsingleton(beanname);
  if (sharedinstance != null && args == null) {
   if (logger.istraceenabled()) {
    if (issingletoncurrentlyincreation(beanname)) {
     logger.trace("returning eagerly cached instance of singleton bean '" + beanname +
       "' that is not fully initialized yet - a consequence of a circular reference");
    }
    else {
     logger.trace("returning cached instance of singleton bean '" + beanname + "'");
    }
   }
   beaninstance = getobjectforbeaninstance(sharedinstance, name, beanname, null);
  }

 @nullable
 public object getsingleton(string beanname) {
  //再点进去
  return getsingleton(beanname, true);
 }
 protected object getsingleton(string beanname, boolean allowearlyreference) {
  // quick check for existing instance without full singleton lock
  object singletonobject = this.singletonobjects.get(beanname);
         //这里由于当前的servicea bean还没完成创建,所以这里singletonobject返回的是空,
        //再看看 issingletoncurrentlyincreation(beanname)这里,由于我们在创建servicea过程中有这么一句beforesingletoncreation(beanname)(不清楚这句的搜索下本文,上面就有讲到),所有这个条件是true。这时我们就会进入if分支中
  if (singletonobject == null && issingletoncurrentlyincreation(beanname)) {
   singletonobject = this.earlysingletonobjects.get(beanname);
           //由于我们是第一次进入这里,所以this.earlysingletonobjects.get(beanname)返回的也是null
           //我们的入参 allowearlyreference是true,会继续进到这个if分支中
   if (singletonobject == null && allowearlyreference) {
    synchronized (this.singletonobjects) {
     // consistent creation of early reference within full singleton lock
     singletonobject = this.singletonobjects.get(beanname);
                    //这里的singletonobject还是null,继续进到if分支
     if (singletonobject == null) {
      singletonobject = this.earlysingletonobjects.get(beanname);
      if (singletonobject == null) {
                            //最终会走到这里,在创建servicea对象之后,属性注入之前,执行了这句 addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean))(不清楚的搜索下本文,上面有说到),所以这里返回的singletonfactory是个lamdba表达式,getearlybeanreference(beanname, mbd, bean))附带了3个参数,第一个beanname是serivcea,mdb是对应servicea的附带servicea元数据信息的rootbeandefinition对象,bean就是创建出来的servicea对象
       objectfactory<?> singletonfactory = this.singletonfactories.get(beanname);
       if (singletonfactory != null) {
                                //这里就会调用getearlybeanreference(beanname, mbd, bean)对servicea对象进行一个getearlybeanreference增强后返回,返回后放置到earlysingletonobjects中,并从singletonfactories中删除
        singletonobject = singletonfactory.getobject();
        this.earlysingletonobjects中,并从.put(beanname, singletonobject);
        this.singletonfactories.remove(beanname);
       }
      }
     }
    }
   }
  }
  return singletonobject;
 }

最终在servicea 这个bean创建完成后,就会从singletonscurrentlyincreation移除掉

 public object getsingleton(string beanname, objectfactory<?> singletonfactory) {
    ......
    finally {
     //在这里从singletonscurrentlyincreation中移除掉
     aftersingletoncreation(beanname);
    }
    if (newsingleton) {
     //将servicea bean对象添加到singletonobjects,registeredsingletons中
     //从singletonfactories,earlysingletonobjects中移除掉
     addsingleton(beanname, singletonobject);
    }
   }
   return singletonobject;
  }
 }

所以整个获取servicea的流程就是这样了,

1、首先去创建servicea这个bean,

  • 由于它有个属性serviceb,在创建完servicea对象后,就会去进行serviceb的属性注入,
  • 这时由于serviceb之前没有生成,这时又会去创建serviceb这个bean,
  • 先创建serviceb对象,然后再进行servicea这个属性的注入,
  • 继续去获取servicea这个bean,第二次进入获取servicea的流程,这时从之前缓存的lambda表达式中获取到之前创建的servicea的引用返回。

2、总结下关键的代码点

  • 创建bean对象之前调用beforesingletoncreation(beanname)将bean对象名字添加到singletonscurrentlyincreation集合中
  • 创建bean对象对应的类实例后调用addsingletonfactory(beanname, () -> getearlybeanreference(beanname, mbd, bean));添加到singletonfactories中
  • 在循环依赖中第二次调用到创建bean对象时,调用getsingleton(beanname, true)时,从singletonfactories中返回对应的早期bean对象的引用,并添加到earlysingletonobjects中

总结

到此这篇关于springboot bean循环依赖实现以及源码分析的文章就介绍到这了,更多相关springboot bean循环依赖内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!