Spring source learning (-) AbstractBeanFactory.getBean's main process

Introduction

Happy Mid-Autumn Festival, you recently read Spring source code, always half-way, very hard to see the getBean part of the source code (IOC), will write a few blog s recently, write down their own feelings.

Entrance

General logic of getBean in AbstractBeanFactory

//Source code of getBean method in AbstractBeanFactory
@Override
public Object getBean(String name, Object... args) throws BeansException {
   return doGetBean(name, null, args, false);
}

The core logic is in: doGetBean.

Logical description:

  1. Get BeanName (BeanFactory removed &, find the corresponding BeanName by alias)
  2. Attempt to retrieve the singleton from the cache and return it if it exists.
  3. Check whether a prototype type type Bean is being created (if so, throw an exception assuming there is a circular reference)
  4. Find the BeanFactory that defines the bean
  5. Merge multiple GernericBeanDefinition s into RootBeanDefinition (if a Bean has a parent Bean, the related attributes of the parent class are merged.)
  6. Guarantee bean dependency initialization first (support for DependOn annotations)
  7. Creating Bean s by Different Scopes
  8. If type replacement is required

Source comments:

/**
 * Return an instance, which may be shared or independent, of 
 the specified bean.
 * Get an instance that can be shared (prototype), independent (singleton), specified
 * @param name the name of the bean to retrieve
 * @param requiredType the required type of the bean to retrieve
 * @param args arguments to use when creating a bean instance 
 * using explicit arguments
 * (only applied when creating a new instance as opposed to 
 retrieving an existing one)
 *              (Use it only when creating a new instance, rather than retrieving an existing bean)
 * @param typeCheckOnly whether the instance is obtained 
   for a type check,not for actual use
 *          Is it just type checking?
 * @return an instance of the bean
 * @throws BeansException if the bean could not be created
 */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) 
      throws BeansException {
   //1. Get the corresponding beanName, remove the BeanFactory & and find the corresponding BeanName by alias
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   //2. Attempt to get a single Spring session from the cache. If the Bean is not created, create the ObjectFactory object of the Bean and expose it earlier to facilitate the solution of cyclic dependency.
   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 + "'");
         }
      }
      //Get the object from the bean instance, if it is FactoryBean, get the object it created
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      //3. Examination of prototype dependencies. If it is a prototype, assume there is a circular reference and throw an exception.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }
      // Check if bean definition exists in this factory.
      // 4. Check whether the bean is defined in BeanFactory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      // If the parent BeanFactory is not empty & currently there is no bean Definition Map not included,
      // Delegate to Father BeanFactory
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            //Delegate to the getBean method that requires parameters
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            // Delegated to the standard getBean method
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) {
         //Not only is type checking, tagging bean s for creation
         // Allow bean s to be merged again
         markBeanAsCreated(beanName);
      }
      try {
         //5. Convert GernericBean Definition to RootBean Definition.
         //If a Bean has a parent Bean, the related attributes of the parent class are merged.
         final RootBeanDefinition mbd = 
                       getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that 
         //  the current bean depends on.
         // 6. Ensure that bean dependencies are initialized first
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
                 // Corresponding to the @DependsOn annotation,
                  /**
                   * Check if there is dependent-on cyclic dependency and throw an exception if there is one.
                   * For example, A depends on B.
                   * B Depending on A, they are configured as follows:
                  @Bean(name="a")
                 @DependsOn("b")public A a () {
                          return new A();}

                      @Bean(name = "b")
                      @DependsOn("a")
                     public B b () {
                          return new B();
                      }

                   * a b is required to be created before it, but b requires a to precede it.
                   * Establish. At this point, a loop is formed. For dependent-on loops, Spring is direct.
                   * throw
                   *
                   *@see org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
                   */
                
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               //Registration, Dependent and Bean Relationships
               registerDependentBean(dep, beanName);
               try {
                  //Create Dependent first
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         // Create bean instance.
         //7. Instances of creating beans
         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;
               }
            });
            bean = 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);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         else {
            String scopeName = mbd.getScope();
            final 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);
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   // 8. Type conversion
   //  requiredType.isInstance (bean) is similar to bean instance of requiredType
   // For true, you can return directly, or force
   //clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)  
   //Only if obj is not null
   if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
         T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
         if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
         }
         return 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;
}

A picture is worth a thousand words (sequence chart)

When I finish the main process, I have the following questions:

  1. The role of getObjectForBeanInstance?
  2. Role of markBean As Created and getMerged LocalBean Definition
  3. What is the DependsOn of bean s?
  4. The Logic of createBean

GettObjectForBean Instance and createBean Logic Next Chat, is expected to be uploaded before 20190 921. Let's start with 2,4.

Supplementary Notes:

Role of markBean As Created and getMerged LocalBean Definition

Simply put, it clears the original RootBean Definition and merges it into a new RootBean Definition through the current GenericBean Definition for BeanFactory use.

What is BeanDefinition

  • BeanDefinition is a minimalist interface that allows BeanFactoryPostProcessor (e.g. Property Placeholder Configurer) to reflect and modify attribute values and other bean metadata.
  • GenericBean Definition is used to define standard beans one-stop. Like other bean Definitions, it allows you to specify a class, attribute values, optional constructor parameter values, and can support derivative relationships by configuring parentName.
  • RootBean Definition represents a combined bean Definition. Spring's BeanFactory uses RootBean Definition to create a specified bean. It may inherit several original Bean Definitions, which are usually GenericBean Definition. RootBean Definition is essentially a runtime "unified" bean definition view.

Search if you are interested

org.springframework.beans.factory.config.BeanDefinition org.springframework.beans.factory.support.GenericBeanDefinition org.springframework.beans.factory.support.RootBeanDefinition

What is the DependOn of a bean?

I initially thought that bean s needed dependencies to process Autowired annotations, but not. IDEA was used to find the place where setDependsOn called BeanDefinition.

The AnnotationConfigUtils.processCommonDefinitionAnnotations method was found as follows:

AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
   abd.setDependsOn(dependsOn.getStringArray("value"));
}

That is to say, in doGetBean

  String[] dependsOn = mbd.getDependsOn();
  if (dependsOn != null) {
       .....
       }

It's support for the @DependOn annotation. I'm not familiar with it. I've never used the @DependOn annotation in my work. I consulted the information from the internet.
The url of the information I checked at that time: https://blog.csdn.net/qq_30257149/article/details/88350320

@ DependOn annotations are used to indicate that the instantiation of a bean A depends on the instantiation of another bean B, but A does not need to hold an object of B.

A long winded sentence

It's not easy to read the source code. At first, I always hold on to a method. After hours, I don't know where I've read. Later, I always swallow dates, blindly seek speed, as if I have seen a lot, but actually I don't know anything. At the beginning of September this year, I did not know whether it was the cooler weather in Beijing or what other reasons. I did not know whether I could calm down, not ask for speed, read one layer at a time, translate one bit at a time, and read only 40 minutes a day. At last, I felt a little clear. I could not help feeling as follows:
It's too confusing to focus only on details.
Encroachment of jujube and blindness
Slow reading may not be fast
Anyway, I'm a beginner.

Next article solves createBean and getObjectForBean Instance

Keywords: Programming Spring Attribute Session

Added by dotti on Sat, 14 Sep 2019 15:48:53 +0300