Spring 源码阅读笔记 (七) 支线 getBean方法解读

Spring 源码阅读笔记 (七)

您的点赞,是我更新下去的动力。

前篇导航

Spring 源码阅读笔记(一)
Spring 源码阅读笔记(二)
Spring 源码阅读笔记(三)
Spring 源码阅读笔记(四)
Spring 源码阅读笔记(五)
Spring 源码阅读笔记(六) 主线 registerBeanPostProcessors解读

前篇回顾

image.png 在上一章节中,阅读了registerBeanPostProcessors方法,因为在其中有遇到GetBean的方法,今天这篇文章中就来讲解一下这个方法,对后续可能会有帮助。

正式开始

GetBean方法位于AbstractBeanFactory的下面。由于我们调用的时候,通常只会传递一个name进入方法,所以很容易可以定位是哪个方法。

public Object getBean(String name) throws BeansException {
   return doGetBean(name, null, null, false);
}


protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
复制代码

有几个入参,这里需要记录一下。

  1. name 实际传入的对象名
  2. requiredType null
  3. args null
  4. typeCheckOnly false

后面来看一下代码。

方法的大概

String beanName = transformedBeanName(name);
Object beanInstance;

// Eagerly check singleton cache for manually registered singletons.
// 急切地检查单例缓存以获取手动注册的单例。
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
   // ...
}

else {
   //....
}

return adaptBeanInstance(name, beanInstance, requiredType);
复制代码

先看一下方法的整体逻辑,他分为两个部分,有一个If区分开来。
在方法的刚开始,尝试从单例缓存中获取我当前的Bean。

这样就分开了两个分支。

  1. 从缓存中获取到了对象
  2. 从缓存中没有获取到对象

方法最终返回的,就是一个实体的实例化过的Bean了。

If为True 代码片段

getSingleton方法

我在往下阅读的时候产生了一丝疑惑,我们看下代码。

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);
}
复制代码

在上方的代码中, 我产生的疑惑是getSingleton(beanName)明明获取到了一个Instance,为什么在下方又获取了一遍Instance赋值给了Bean Instance,而不是直接把刚刚获取到的shareInstance直接给BeanInstance,带着这个问题,我打开了getSingleton方法。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            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;
}
复制代码

看这个方法,里面这么多if,看起来不用太害怕。这里关注的东西只有一个singletonObjects

/** 单例对象缓存:bean 名称到 bean 实例。 */
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
复制代码

就是从这个地方获取,然后返回回去的,当前Map存在的话,就把实例化的对象返回出去,不存在就返回Null值。

getObjectForBeanInstance方法

还记得我在上一段提的问题吗。

为什么在下方又获取了一遍Instance赋值给了Bean Instance,而不是直接把刚刚获取到的shareInstance直接给BeanInstance

在这个方法中会有揭晓。

protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

   if (BeanFactoryUtils.isFactoryDereference(name)) {
      // ... 假设代码块进不来
      return beanInstance;
   }

   
   if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
      return beanInstance;
   }

   Object object = null;
   if (mbd != null) {
      mbd.isFactoryBean = true;
   }
   else {
      object = getCachedObjectForFactoryBean(beanName);
   }
   if (object == null) {
      // Return bean instance from factory.
      // Caches object obtained from FactoryBean if it is a singleton.
      if (mbd == null && containsBeanDefinition(beanName)) {
         mbd = getMergedLocalBeanDefinition(beanName);
      }
      boolean synthetic = (mbd != null && mbd.isSynthetic());
      object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
   }
   return object;
}
复制代码

通过上面的代码可以看出来,好像他这里返回的Object,其实就是把穿进来的那个东西原封不动的返回回去了。
因此得知,shareInstance == BeanInstance。

If为False 代码片段

第一段代码

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}

protected boolean isPrototypeCurrentlyInCreation(String beanName) {
   // prototypesCurrentlyInCreation 是一个ThreadLocal
   Object curVal = this.prototypesCurrentlyInCreation.get();
   return (curVal != null &&
         (curVal.equals(beanName) || (curVal instanceof Set<?> set && set.contains(beanName))));
}

复制代码

这一段比较简单一点,只是判断一下当前的Bean是否在当前线程中正在创建。是的话抛出异常。

第二段代码

BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
   // Not found -> check parent.
   // 没有找到 -> 检查父级工厂
   String nameToLookup = originalBeanName(name);
   if (parentBeanFactory instanceof AbstractBeanFactory abf) {
      return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
   }
   else if (args != null) {
      // Delegation to parent with explicit args.
      return (T) parentBeanFactory.getBean(nameToLookup, args);
   }
   else if (requiredType != null) {
      // No args -> delegate to standard getBean method.
      return parentBeanFactory.getBean(nameToLookup, requiredType);
   }
   else {
      return (T) parentBeanFactory.getBean(nameToLookup);
   }
}
复制代码

方法刚进入,最外面的If,判断当前的工厂有没有父级工厂,没有的话,这个If就不走了,有的话,进行再次判断,判断当前工厂中的,BeanDefinition中有没有当前要获取的Bean信息,没有的话不进入If,有的话进入If。这里假设条件成立,往下看。

NameToLookup变量,就是把Name转换了一下。这个不用在意,把这个变量看成BeanName就可以了

在内部的第一个判断,判断父级工厂是不是继承自AbstractBeanFactory,如果是的话,调用父级工厂的doGetBean,也就是父级的当前方法。把他当成递归理解应该可以吧。

在内部的第二个、第三个、第四个判断,意思相同,通过不同的选择调用父级工厂不同的getBean方法。

第三段代码

if (!typeCheckOnly) {
   markBeanAsCreated(beanName);
}

protected void markBeanAsCreated(String beanName) {
   if (!this.alreadyCreated.contains(beanName)) {
      synchronized (this.mergedBeanDefinitions) {
         if (!this.alreadyCreated.contains(beanName)) {
            // Let the bean definition get re-merged now that we're actually creating
            // the bean... just in case some of its metadata changed in the meantime.
            clearMergedBeanDefinition(beanName);
            this.alreadyCreated.add(beanName);
         }
      }
   }
}
复制代码

这个方法,由于我们在调用doGetBean方法时。传入的typeCheckOnly为False,所以这里一定会进入,这个方法的最终的目的是,向alreadyCreated这个Set中去追加,意思就是设置当前的Bean已经是创建状态。

后面就是Bean创建的部分了。因为在当前的Bean工厂中和父级工厂中都没有找到已经创建好的,所以要去创建Bean

第四段代码

if (requiredType != null) {
   beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
复制代码

requiredType在起初方法调用时传入的是Null,所以这个if不会进入。

下面这两行代码,一个看样子是获取BeanDefinition,一个是检查这个BeanDefintion,这里就不抠细节了。

第五段代码

// Guarantee initialization of beans that the current bean depends on.
// 保证当前 bean 所依赖的 bean 的初始化。
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);
      }
   }
}
复制代码

这段代码的意思刚开始看起来比较繁琐,这里需要解释一下Spring的一个功能。在Bean标签上配置一个depends-on,这个就是配置依赖关系。
假设BeanB依赖BeanA那么,BeanA就要比BeanB先创建Bean。

这个方法的目的就是为了保证这样的顺序,可以看到在这个方法的中间,getBean(dep)就是关键。

第六段代码

// Create bean instance.
if (mbd.isSingleton()) {
   sharedInstance = getSingleton(beanName, () -> {
      try {
         return createBean(beanName, mbd, args);
      }
      catch (BeansException ex) {
         destroySingleton(beanName);
         throw ex;
      }
   });
   beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      beforePrototypeCreation(beanName);
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
      afterPrototypeCreation(beanName);
   }
   beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

else {
   String scopeName = mbd.getScope();
   if (!StringUtils.hasLength(scopeName)) {
      throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
   }
   Scope scope = this.scopes.get(scopeName);
   if (scope == null) {
      throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
   }
   try {
      Object scopedInstance = scope.get(beanName, () -> {
         beforePrototypeCreation(beanName);
         try {
            return createBean(beanName, mbd, args);
         }
         finally {
            afterPrototypeCreation(beanName);
         }
      });
      beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
   }
   catch (IllegalStateException ex) {
      throw new ScopeNotActiveException(beanName, scopeName, ex);
   }
}
复制代码

下面这一段代码很轻松就可以看出来了,他是根据xml中配置的scope作用域,来判断这么去创建Bean。创建Bean的方法就是createBean方法。

这个createBean涉及的知识点过多,我们这里先跳过,我在后面单开文章讲解。

第七段方法

return adaptBeanInstance(name, beanInstance, requiredType);

<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
   // Check if required type matches the type of the actual bean instance.
   // 检查所需类型是否与实际 bean 实例的类型匹配。
   if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
         Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
         if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
         }
         return (T) convertedBean;
      }
      catch (TypeMismatchException ex) {
         if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                  ClassUtils.getQualifiedName(requiredType) + "'", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}
复制代码

这里有一个if,但是很明显,通过我们的这个流程进到这里的,requiredType是Null,所以if不会进入,那么直接返回了Bean。

告一段落

这篇文章到这里就结束了,讲这个方法的目的呢很明显,如果不读的话,不知道getBean到底get的是什么,假设如果不看这个,我看到getBean,下意识就是获取了一个Bean,但是在初期这个Bean还没有实例化的话,下意识的以为这里会get出个null出来,所以这里也就先解析。

在这一篇文章中引出了一个点。getBean是先获取,如果获取不到的话,他回去创建。那么这个创建的流程是什么样的。很多文章都有讲到,Spring是先实例化Bean,在初始化Bean什么的,具体到底是不是这样的。在后面的文章拭目以待。

都看到这了,点个赞再走呗,宝~

结束语

写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。

猜你喜欢

转载自juejin.im/post/7080175223420485662