Notas de lectura del código fuente de Spring (7) Interpretación del método branch getBean

Notas de lectura del código fuente de Spring (7)

Tus likes son la motivación para seguir actualizándome.

Navegación anterior

Notas de lectura del código fuente de Spring (1)
Notas de lectura del código fuente de Spring (2)
Notas de lectura del código fuente de Spring (3)
Notas de lectura del código fuente de Spring (4)
Notas de lectura del código fuente de Spring (5)
Notas de lectura del código fuente de Spring (6) Interpretación de la línea principal registerBeanPostProcessors

Revisión anterior

imagen.pngEn el capítulo anterior, leí el método registerBeanPostProcessors, porque encontré el método GetBean en él. Hoy, explicaré este método en este artículo, que puede ser útil en el futuro.

comienza oficialmente

El método GetBean se encuentra debajo de AbstractBeanFactory. Dado que generalmente solo pasamos un nombre al método cuando lo llamamos, es fácil ubicar qué método es.

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

Hay varios parámetros de entrada que deben registrarse aquí.

  1. nombre El nombre real del objeto pasado en
  2. tipo requerido nulo
  3. argumentos nulos
  4. tipoCheckOnly falso

Mira el código más tarde.

método aproximado

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

Veamos primero la lógica general del método, que se divide en dos partes, que se distinguen por un If.
Al comienzo del método, intente obtener mi bean actual del caché de singleton.

Esto separa las dos ramas.

  1. objeto obtenido del caché
  2. Objeto no recuperado del caché

El retorno final del método es el Bean instanciado de una entidad.

Si es un fragmento de código verdadero

getSingleton 方法

Cuando leí, tuve una pequeña duda, veamos el código.

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出来,所以这里也就先解析。

Se dibuja un punto en este artículo. getBean se obtiene primero, y si no se puede obtener, volverá y lo creará. Entonces, ¿cómo es el flujo de esta creación? Muchos artículos han mencionado que Spring instancia Beans primero y luego inicializa Beans o algo así.¿Es este el caso? Esperamos el próximo artículo.

He visto esto, por favor dale me gusta y vete, tesoro~

Observaciones finales

El propósito de escribir artículos es ayudarlo a consolidar su conocimiento. Puede señalar cosas malas o incorrectas en el área de comentarios. Si lees el artículo y crees que te es útil, puedes darle me gusta. Si encuentras algunas preguntas que te generan dudas, o si no las entiendes, puedes comentarlas y agregarme en WeChat, y debes saber todo. Por supuesto, también espero hacerme amigo de todos y aprender unos de otros.

Supongo que te gusta

Origin juejin.im/post/7080175223420485662
Recomendado
Clasificación