DoGetBean source code:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

   // First convert the name passed into the container's real beanName
   // There are three ways to get beanName
   // One is the original beanName, one is the ampersand, and one is the alias
   final String beanName = transformedBeanName(name);
   Object bean;

   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   // If you have previously created an instance of a singleton Bean, and the getBean method is called with an empty argument, the logic of the plane is executed
   // Args is required to be null because if args is present, further assignment is required, so it cannot be returned directly
   if(sharedInstance ! =null && args == null) {
      if (logger.isTraceEnabled()) {
         // If the Bean is still being created, it is a circular reference
         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 + "'"); }}Return getObject if it is a plain bean, or getObject if it is a FactoryBean
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

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

      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      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.
            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(! typeCheckOnly) { markBeanAsCreated(beanName); }try {
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         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); }}}// Create bean instance.
         // If BeanDefinition is singleton
         if (mbd.isSingleton()) {
            // An anonymous inner class is used to create Bean instance objects and register them with dependent objects
            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);
                  throwex; }}); 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);
         throwex; }}// Check if required type matches the type of the actual bean instance.
   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 newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}return (T) bean;
}
Copy the code

We discussed the code in doGetBean to fetch the bean from the cache. The else in doGetBean will handle cases where the scope of the bean is prototype or singleton mode but the bean does not yet exist in the cache:Spring also designs a cache list for Scope’s Bean for Prototype

if (isPrototypeCurrentlyInCreation(beanName)) {
   throw new BeanCurrentlyInCreationException(beanName);
}
Copy the code
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   return(curVal ! =null &&
         (curVal.equals(beanName) || (curVal instanceofSet && ((Set<? >) curVal).contains(beanName)))); }Copy the code

In contrast to the singleton set, ThreadLocal records only the scope prototype Bean created by the current thread. If (true) above proves that there is a loop dependency.


After passing the cyclic dependency check, see if the container has a parent. If it does, and there is no BeanDefinition instance of the bean in the current container, try to recursively query from the parent

To prevent the previous beanName from being transformed, append & and call the doGetBean or getBean method of the parent class, or doGetBean if the parent class is AbstractBeanFactory


If the current container contains a BeanDefinition instance of the bean, execution continues

// typeCheckOnly is used to determine whether getBean() is called only to get the bean for type checking and not to create the bean
if(! typeCheckOnly) {// Create the bean instead of just doing type checking
   markBeanAsCreated(beanName);
}
Copy the code

So inside the markBeanAsCreated method,

protected void markBeanAsCreated(String beanName) {
   // Double check locking mechanism
   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.
            // Set the status of the previously merged RootBeanDefinition to true
            // Indicates that the data needs to be merged again to prevent changes to the original data
            clearMergedBeanDefinition(beanName);
            // add the names of alreadyCreated or currently created beans to the alreadyCreated cache
            this.alreadyCreated.add(beanName); }}}}Copy the code

There is a double lock checking mechanism. The name of the created Bean is added to the alreadyCreated (type Set) cache. Before adding to the cache, the original MergedBeanDefinition is Set to the previous identifier to be cleared. The goal is to re-merge the subclass and parent beanDefinitions when they are retrieved from the container. This prevents the metadata from being changed and the BeanDefinition from being created using the original data

protected void clearMergedBeanDefinition(String beanName) {
   RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
   if(bd ! =null) {
      bd.stale = true; }}Copy the code

ClearMergedBeanDefinition back the container to obtain RootBeanDefinition instances, and combine the instance needs to be the state of the set to true (mentioned before, as long as the attribute specifies the parent, The two Beandefinitions are combined into one.)


Return to doGetBean, then call getMergedLocalBeanDefinition method to merge BeanDefinition of parents and children, into the method:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
   // Quick check on the concurrent map first, with minimal locking.
   RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
   if(mbd ! =null && !mbd.stale) {
      return mbd;
   }
   return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
Copy the code

Fetch the merged RootBeanDefinition instance from the mergedBeanDefinitions cache. If stale is true, the mergedBeanDefinition instance will be returned.


Go back to the doGetBean, get the BeanDefinition, and verify the validity of the relevant instance

checkMergedBeanDefinition(mbd, beanName, args);
Copy the code

Into the checkMergedBeanDefinition method:

protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
      throws BeanDefinitionStoreException {

   if (mbd.isAbstract()) {
      throw newBeanIsAbstractException(beanName); }}Copy the code

Let’s see if RootBeanDefinition is abstract.


Go back to the doGetBean and try to get explicit dependencies from the BeanDefinition, and check for circular dependencies if you are dependent -onIf there are no circular dependencies, the associated dependencies are registered

registerDependentBean(dep, beanName);
Copy the code
public void registerDependentBean(String beanName, String dependentBeanName) {
   String canonicalName = canonicalName(beanName);

   synchronized (this.dependentBeanMap) {
      // computeIfAbsent: If the value corresponding to the key is empty, the return value of the second parameter is saved and returned
      DependentBeanMap contains a collection of referenced beans for the current Bean
      // If the Bean name is userInfo, userInfo has an attribute of type Human
      Human =[userInfo]
      Set<String> dependentBeans =
            this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
      if(! dependentBeans.add(dependentBeanName)) {return; }}synchronized (this.dependenciesForBeanMap) {
      Set<String> dependenciesForBean =
            this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); }}Copy the code

The first registration is a dependentBeanMap (key is the name of the dependentBean, value is the list of dependentBean names)


The second re-registration writes the opposite key/value pair to the dependenciesForBeanMap


Back to doGetBean, after the explicit dependency registration is performed, getBean(DEP) is recursively called to create the dependent bean. After that, different bean creation operations are performed for different scopes, including Singleton, Prototype, and others.


Except Prototype is called directlycreateBean(beanName, mbd, args)In addition to creating the Bean instance, scope= encapsulates createBean in an anonymous parameterEnter the scope.get() method

Object get(String name, ObjectFactory
        objectFactory);
Copy the code

As you can see, the following anonymous function implements the getObject method of the ObjectFactory and calls the createBean method to create an instance that fits the Scope.


Scope = singleton:

if (mbd.isSingleton()) {
   // An anonymous inner class is used to create Bean instance objects and register them with dependent objects
   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.
         // Explicitly remove the bean instance from the singleton cache
         // Because it may already exist in singleton mode to resolve cyclic dependencies, it is destroyed
         destroySingleton(beanName);
         throwex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }Copy the code

Enter the getSingleton method:Is also to receive aObjectFactoryObject then implements its getObject method.


Enter the createBean:

protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException;
Copy the code

This is an abstract method that requires subclasses to implement.


Back to the getSingleton method above:

public Object getSingleton(String beanName, ObjectFactory
        singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            throw new BeanCreationNotAllowedException(beanName,
                  "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                  "(Do not request a bean from a BeanFactory in a destroy method implementation!) ");
         }
         if (logger.isDebugEnabled()) {
            logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throwex; }}catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); }}throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
         }
         if(newSingleton) { addSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code

Lock the first level cache singletonObjects. After obtaining the lock, try again to obtain the instance from the first level cache in case another thread has created it. If it cannot obtain the instance, start to create it:


Let’s see if the container is currently destroying all singletons: singletonsCurrentlyInDestructionA flag.


Beforesington Creation(beanName) after verification, enter:

protected void beforeSingletonCreation(String beanName) {
    / / inCreationCheckExclusions cache cannot load current bean directly,
    // It is mainly used in web container interceptors, so it can be ignored here because it definitely does not exist
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw newBeanCurrentlyInCreationException(beanName); }}Copy the code

The first condition of if can be ignored. The second condition is an attempt to place beanName in the list of singleton names being created. Failure to add beanName will throw an exception because the normal process of creating a bean is not supposed to enter this. If beanName appears in the list of names being created, it indicates that the same bean was created prior to this operation, which should have been obtained when the first step of doGetBean was to fetch the bean instance from the level 3 cache.

In the concurrent scenario, neither thread gets a singleton in the level 3 cache, and they end up here.


Back to the getSingleton method above, it’s time to create and get the bean instance: newSingletonSet to true for subsequent callsaddSingletonTo add a level 1 cache.


Skip exception handling and look at finally:Enter the afterSingletonCreation:

protected void afterSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); }}Copy the code

Due to the bean instance is created, so have the is creating removes beanName singletonsCurrentlyInCreation bean name list


Back outside, the next step is to check if it is a newly created singleton, with the flag bit already true, and enter addSingleton:

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      // After the Bean instance is created, only the level 1 cache and the order in which beanName is registered are retained, and the rest is cleared
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName); }}Copy the code

After executing addSingleton, the full bean instance will be returned


Back to the creation singleton logic for doGetBean, which is executed once the full bean instance is returned

// If it is a normal bean, return it directly, is a FactoryBean, return its getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
Copy the code


Create scope for PrototypeEnter thebeforePrototypeCreation:

protected void beforePrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal == null) {
      this.prototypesCurrentlyInCreation.set(beanName);
   }
   else if (curVal instanceof String) {
      Set<String> beanNameSet = new HashSet<>(2);
      beanNameSet.add((String) curVal);
      beanNameSet.add(beanName);
      this.prototypesCurrentlyInCreation.set(beanNameSet);
   }
   else{ Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.add(beanName); }}Copy the code

To the type of ThreadLocal prototypesCurrentlyInCreation (the current thread is to create the Prototype of the bean name list) to add the record of the bean, avoid circular dependencies, said the bean is created.


PrototypeInstance = createBean(beanName, MBD, args) is also called to erase the previously registered Bean information

afterPrototypeCreation(beanName);
Copy the code
protected void afterPrototypeCreation(String beanName) {
   Object curVal = this.prototypesCurrentlyInCreation.get();
   if (curVal instanceof String) {
      this.prototypesCurrentlyInCreation.remove();
   }
   else if (curVal instanceof Set) {
      Set<String> beanNameSet = (Set<String>) curVal;
      beanNameSet.remove(beanName);
      if (beanNameSet.isEmpty()) {
         this.prototypesCurrentlyInCreation.remove(); }}}Copy the code


Go back to doGetBean, which will be called later

bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
Copy the code

Get the bean instance or bean instance created by the beanFactory


And then finally looking at the other cases,To create bean instances, choose the appropriate method to instantiate the bean based on the lifecycle range, such as Request, which ensures that one instance is generated per request.


Finally, the doGetBean does a type check and returns an instance:

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 newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}return (T) bean;
Copy the code