In previous articles, we briefly covered the loading process of bean definitions. In this article, we will focus on the creation process of bean instances.


How the bean instance is created

ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
context.getBean("beanDemo");
Copy the code

First of all, the code above uses the getBean method. Is the entry to create the bean inside the getBean?

As you can see from the previous section, singleton beans can be instantiated ahead of time because they can be used more efficiently. The prototype bean, or multiinstance bean, is instantiated at getBean time. And the singleton bean and the prototype bean instantiation process is no different, both through the getBean method, at the start of the early instantiation is also using the getBean method.

Bean instances are created and configured as follows:

  • The way a method is constructed

There are two ways to create an instance from a constructor: a no-parameter constructor and a parameterized constructor

Here is how the no-argument constructor is configured:

public class ConstructorBean {

    public ConstructorBean(a) {
        System.out.println("No-parameter constructor......"); }}Copy the code
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean" />
Copy the code

Here’s how the parameter constructor is configured:

public class ConstructorBean {

    public ConstructorBean(String name, int age) {
        System.out.println("Parameter constructor......");
        System.out.println(name + "_"+ age); }}Copy the code
<bean id="constructorBean" class="edu.demo.spring.instantiate.ConstructorBean">
   <constructor-arg index="0" value="Cui flower" />
   <constructor-arg index="1" value="18" />
</bean>
Copy the code

The following output is displayed:

  • Static factory method
public class InstantiateFactory {

    public static String getStaticFactoryMethod(a) {
       return "Static factory method to create bean......"; }}Copy the code
<bean id="boyService" class="edu.demo.spring.instantiate.InstantiateFactory"
      factory-method="getStaticFactoryMethod"> <! --<property name="" ref=""></property>-->
</bean>
Copy the code
  • Non-static factory methods
public class InstantiateFactory {

   public String getMemberFactoryMethod(String name) {
      return "Non-static factory method to create bean......"; }}Copy the code
<bean id="instantiateFactory" class="edu.demo.spring.instantiate.InstantiateFactory" />

<bean id="grilService" factory-bean="instantiateFactory"
   factory-method="getMemberFactoryMethod"> <! --<constructor-arg index="0" value="Hello" />-->
</bean>
Copy the code
  • Designated factory method

You need to inherit the FactoryBean interface:

public class BoyFactoryBean implements FactoryBean<Boy> {

   @Override
   public Boy getObject(a) throws Exception {
      return new Lad("niulang");
   }

   @Override
   publicClass<? > getObjectType() {returnBoy.class; }}Copy the code
<bean name="boyService2" class="edu.demo.spring.instantiate.BoyFactoryBean">
</bean>
Copy the code

If you want to get BoyFactoryBean itself, you need to prefix it with “&”, otherwise you return the bean in getObject, which is the bean instance created by FactoryBean

Object lsfb2 = context.getBean("boyService2");
System.out.println(lsfb2);
Object lsfb4 = context.getBean("&boyService2");
System.out.println(lsfb4);
BoyFactoryBean lsfb = (BoyFactoryBean) context.getBean("&boyService2");
System.out.println(lsfb);
System.out.println(lsfb.getObject());
Copy the code

The output is as follows:


The process of instantiating beans

From AbstractApplicationContext class the refresh () method to look, there’s a step, some single example bean is instantiated in advance:

// Complete the initialization of the bean factory, initializing all non-lazy-loaded singleton beans
finishBeanFactoryInitialization(beanFactory);
Copy the code

Click here to see the implementation:

/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
   // Initialize conversion service for this context.
   // Instantiate the cast service
   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
      beanFactory.setConversionService(
            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
   }

   // Register a default embedded value resolver if no bean post-processor
   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
   // at this point, primarily for resolution in annotation attribute values.
   // Make sure beanFacotory holds a parser for embedded values
   if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
   // Pre-instantiate LoadTimeWeaverAware beans
   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
   for (String weaverAwareName : weaverAwareNames) {
      getBean(weaverAwareName);
   }

   // Stop using the temporary ClassLoader for type matching.
   beanFactory.setTempClassLoader(null);

   // Allow for caching all bean definition metadata, not expecting further changes.
   // Freeze the configuration. The bean definition information cannot be changed for instantiation
   beanFactory.freezeConfiguration();

   // Instantiate all remaining (non-lazy-init) singletons.
   // Instantiate the singleton bean
   beanFactory.preInstantiateSingletons();
}
Copy the code

It then goes to the preInstantiateSingletons method:

    /** A collection of bean definition names */ in the order in which they were registered
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
Copy the code
  // Iterate over a copy to allow for init methods which in turn register new bean definitions.
   // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
   // Get all the bean definition names
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
Copy the code

As you can see from the above code, this method gets all the bean definition names as soon as it comes in. The list of bean definitions is decorated with the volatile keyword.

// Trigger initialization of all non-lazy singleton beans...
// Triggers the initialization of all non-lazy-loaded singleton beans
for (String beanName : beanNames) {
   // Get the merged bean definition information
   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
   // If the bean definition is not abstract and is singleton and not lazily loaded, proceed
   if(! bd.isAbstract() && bd.isSingleton() && ! bd.isLazyInit()) {// Continue if it is a factory bean, otherwise execute the getBean method directly
      if (isFactoryBean(beanName)) {
         // Get the bean, which is a factory bean
         Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
         if (bean instanceofFactoryBean) { FactoryBean<? > factory = (FactoryBean<? >) bean;// Determine if instantiation is urgently needed
            boolean isEagerInit;
            if(System.getSecurityManager() ! =null && factory instanceofSmartFactoryBean) { isEagerInit = AccessController.doPrivileged( (PrivilegedAction<Boolean>) ((SmartFactoryBean<? >) factory)::isEagerInit, getAccessControlContext()); }else {
               isEagerInit = (factory instanceofSmartFactoryBean && ((SmartFactoryBean<? >) factory).isEagerInit()); }// If the bean needs to be instantiated immediately, call the getBean method
            if(isEagerInit) { getBean(beanName); }}}else {
         // Get the normal beangetBean(beanName); }}}Copy the code

A FactoryBean is a bean, but it is a bean that produces beans. If you use getBean directly to get the beans it produces, you need to use getBean(& + beanName) to get the factory bean.


DoGetBean method introduction

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

Name is the name of the bean definition, requiredType is the type required by the bean, args is the parameter explicitly passed, and typeCheckOnly is type checking.

Args refers to arguments in the following code:

ConstructorBean constructorBean = (ConstructorBean) context.getBean("constructorBean".new Object[]{1.2.3});
Copy the code

Using the example just above, then debug to the doGetBean method to see:

The first step into the method is to execute the transformedBeanName method:

String beanName = transformedBeanName(name);
Object bean;
Copy the code

The transformedBeanName method gets the standard bean definition name. What is the standard bean definition name? Because when configuring the bean definition, you can define some aliases for the bean.

This bean definition is also available when using getBean(” alias “). The main reason is the underlying aliasMap, where the key value is the alias and the value is the actual bean definition name.

/** Map from alias to canonical name. */
private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);
Copy the code
/**
 * Return the bean name, stripping out the factory dereference prefix if necessary,
 * and resolving aliases to canonical names.
 * @param name the user-specified name
 * @return the transformed bean name
 */
protected String transformedBeanName(String name) {
   return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
Copy the code

Here again call BeanFactoryUtils. TransformedBeanName and canonicalName two methods:

/** * returns the bean name, removing the factory dereference prefix * if necessary@param name the name of the bean
 * @return the transformed name
 * @see BeanFactory#FACTORY_BEAN_PREFIX
 */
public static String transformedBeanName(String name) {
   Assert.notNull(name, "'name' must not be null");
   // If the bean name does not contain the & prefix, it is returned
   if(! name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {return name;
   }
   // Remove the dereference prefix of the bean name, that is, the & prefix
   return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
      do {
         beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
      }
      while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
      return beanName;
   });
}
Copy the code
/** * This method is used to get the real bean name *@param name the user-specified name
 * @return the transformed name
 */
public String canonicalName(String name) {
   String canonicalName = name;
   // Handle aliasing...
   String resolvedName;
   do {
      resolvedName = this.aliasMap.get(canonicalName);
      if(resolvedName ! =null) { canonicalName = resolvedName; }}while(resolvedName ! =null);
   return canonicalName;
}
Copy the code

CanonicalName uses do… The while loop gets the real bean name. Here’s a quick example:

<bean id="constructorBean" name="bean1,bean2,bean3,bean4" class="edu.demo.spring.instantiate.ConstructorBean">
   <constructor-arg index="0" value="Cui flower" />
   <constructor-arg index="1" value="18" />
</bean>

<alias name="bean2" alias="a"/>
Copy the code
ConstructorBean constructorBean = (ConstructorBean) context.getBean("a");
Copy the code

ConstructorBean is configured with four individual names bean1,bean2,bean3, and bean4, as well as an alias, a, for the alias name bean2.

Bean2: alias bean2: alias bean2: alias bean2: alias bean2

The following figure shows the aliasMap for the bean’s alias definition:

Now it’s clear why do is used here… The while loop retrieves the standard bean name because the bean can have an alias. When resolvedName is empty, that is, there are no aliases left, the loop is broken and the real bean name is retrieved.

Next use if… Else is divided into two parts. Let’s look at the first part:

// Eagerly check singleton cache for manually registered singletons.
// Get the instantiated singleton bean from the cache
Object sharedInstance = getSingleton(beanName);
// Execute the following code if the bean instance exists and the explicitly passed argument is empty
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 + "'"); }}If the bean is a FactoryBean, then create an instance of it
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
Copy the code

Let’s start with the getSingleton method

/** Caches of singleton beans */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Caches for singleton factories */
private finalMap<String, ObjectFactory<? >> singletonFactories =new HashMap<>(16);

/** Cache of preloaded singleton beans */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // First get the bean instance from the cache of the singleton bean
   Object singletonObject = this.singletonObjects.get(beanName);
   // Execute the following if not obtained and the bean is being created
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      / / lock
      synchronized (this.singletonObjects) {
         // Get the bean instance from the cache of the preloaded singleton bean
         singletonObject = this.earlySingletonObjects.get(beanName); ,// If you still don't get it and need to create an earlier reference
         if (singletonObject == null && allowEarlyReference) {
            // Get the singleton factory from beanNameObjectFactory<? > singletonFactory =this.singletonFactories.get(beanName);
            // If the factory is not empty
            if(singletonFactory ! =null) {
               / / get a bean
               singletonObject = singletonFactory.getObject();
               // into the cache of the preloaded singleton bean
               this.earlySingletonObjects.put(beanName, singletonObject);
               // Remove the bean from singletonFactories,
               // singletonFactories are not needed because earlySingletonObjects are already added to it
               this.singletonFactories.remove(beanName); }}}}return singletonObject;
}
Copy the code

If the above method does not get the bean instance, use the else method below:

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

The first is to check whether the prototype bean is already under construction to detect cyclic dependencies, such as bean2 being used to create bean1 and bean1 being used to create bean2, which will throw an exception.

The following code is used to determine the parent factory:

// Check if bean definition exists in this factory.
// First, get the parent factory
BeanFactory parentBeanFactory = getParentBeanFactory();
// If the parent factory is not empty and does not contain the bean definition locally, fetch it from the parent factory
if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
   // Not found -> check parent.
   // This step is to restore the original bean name, because there is a factoryBean,
   // Remove the prefix from the top and add it back here
   String nameToLookup = originalBeanName(name);
   // Create a bean instance from the parent class
   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); }}Copy the code

Can see from the above code, parentBeanFactory getBean, getBean method is used here, is also a recursive call.

if(! typeCheckOnly) { markBeanAsCreated(beanName); }Copy the code

The above code is to determine that, if this is more than a type check, it is to record that the bean has been created. Here is the markBeanAsCreated method:

/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

/** Names of beans that have already been created at least once. */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

protected void markBeanAsCreated(String beanName) {
   // First, determine whether the bean is included in the collection of beans already created
   if (!this.alreadyCreated.contains(beanName)) {
      / / lock
      synchronized (this.mergedBeanDefinitions) {
         // Double lock
         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.
            // Clear the merged bean definition and remerge the bean definition.
            // In case the bean definition changes
            clearMergedBeanDefinition(beanName);
            // Add beanName to the set already created
            this.alreadyCreated.add(beanName); }}}}Copy the code

Then enter the following code again:

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
// Get the dependent bean
String[] dependsOn = mbd.getDependsOn();
if(dependsOn ! =null) {
   // Loop over the dependent beans
   for (String dep : dependsOn) {
      // Check whether it is a cyclic dependency, and throw an exception if it is
      if (isDependent(beanName, dep)) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
      }
      // Register the dependent bean
      registerDependentBean(dep, beanName);
      try {
         // Get the dependent bean
         getBean(dep);
      }
      catch (NoSuchBeanDefinitionException ex) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}Copy the code

Here first to obtain the combined bean definitions, then detect the bean is abstract, and if so, it throws an exception, the judgment within checkMergedBeanDefinition method.

Then check whether the bean is dependent on other beans. If there are dependencies, register the dependent bean with a map of dependencies. Then call getBean method to instantiate the dependent bean first.

Finally, if no bean instance is available, execute the following code to create the bean instance:

// Create bean instance.
// Scope handling: singleton, prototype, others
// Check whether it is a singleton
if (mbd.isSingleton()) {
   // Get the singleton bean, if not, create it, and cache it in the collection of singleton beans
   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; }});// Do the factory bean processing
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// Processing of the prototype bean
else if (mbd.isPrototype()) {
   // It's a prototype -> create a new instance.
   Object prototypeInstance = null;
   try {
      // Check for cyclic dependencies on multiple instances of beans and record them
      beforePrototypeCreation(beanName);
      / / create a bean
      prototypeInstance = createBean(beanName, mbd, args);
   }
   finally {
     // Release the record of the cyclic dependency check
      afterPrototypeCreation(beanName);
   }
   // Do the factory bean processing
   bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// Processing of other scope beans
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, () -> {
        // Loop the dependency check and make a note
         beforePrototypeCreation(beanName);
         try {
            / / create a bean
            return createBean(beanName, mbd, args);
         }
         finally {
            // Release the record of the cyclic dependency checkafterPrototypeCreation(beanName); }});// Do the factory bean processing
      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); }}Copy the code

The above creation is divided into three parts, singleton, multiinstance, and other scoped beans, and the process is roughly the same, with the createBean method being called.

GetSingleton method

Let’s look at the getSingleton method for the singleton bean:

/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 * @param beanName the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 * with, if necessary
 * @return the registered singleton object
 */
public Object getSingleton(String beanName, ObjectFactory
        singletonFactory) {}
Copy the code

This method is used to get the singleton bean and calls the method that created the bean.

synchronized (this.singletonObjects) {
   Object singletonObject = this.singletonObjects.get(beanName);
}
Copy the code

SingletonObjects, as mentioned above, holds the set of singleton beans that have already been instantiated. If not, create the singleton bean from singletonObjects.

/** Flag that indicates whether we're currently within destroySingletons. */
private boolean singletonsCurrentlyInDestruction = false;

/** Collection of suppressed Exceptions, available for associating related causes. */
@Nullable
private Set<Exception> suppressedExceptions;
Copy the code
// If the singleton bean is not available, create it
if (singletonObject == null) {
    // Determine if the singleton bean is being destroyed and throw an exception if it is
    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 + "'");
    }
    // The process before the singleton bean is created is also recorded
    beforeSingletonCreation(beanName);
    // Whether the singleton bean is newly created
    boolean newSingleton = false;
    // Record exceptions generated during the creation process, probably yes, I guess, haha
    boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    if (recordSuppressedExceptions) {
       this.suppressedExceptions = newLinkedHashSet<>(); }}Copy the code

Then look at being Creative Creation

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
      Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions =
      Collections.newSetFromMap(new ConcurrentHashMap<>(16));

protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw newBeanCurrentlyInCreationException(beanName); }}Copy the code

The judgment and add inCreationCheckExclusions is ruled out the bean name set, that is to say the bean will not be created. In the name of the bean singletonsCurrentlyInCreation record is currently being created.

Here is the code to create it:

try {
   //singletonFactory executes the create bean code above
   singletonObject = singletonFactory.getObject();
   // Once created, mark it as a new singleton bean
   newSingleton = true;
}
Copy the code

Then the following code does some caching:

finally {
   if (recordSuppressedExceptions) {
      this.suppressedExceptions = null;
   }
   // Remove the record
   afterSingletonCreation(beanName);
}
// If it is a new singleton bean, do some caching
if (newSingleton) {
   addSingleton(beanName, singletonObject);
}
Copy the code

Look at the afterSingletonCreation method, which removes the current bean from the collection being created

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

Then here is the cache method:

protected void addSingleton(String beanName, Object singletonObject) {
   synchronized (this.singletonObjects) {
      this.singletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName); }}Copy the code

The method is simpler. Add the instantiated singleton bean to the singletonObjects collection, removed from singletonFactories and earlySingletonObjects because it is already instantiated. It was also added to the registeredSingletons collection.

Prototype bean

Let’s look at the processing of the prototype bean:

/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
      new NamedThreadLocal<>("Prototype beans currently in creation");

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
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

From the above source code, you can see, prototypesCurrentlyInCreation using ThreadLocal, can avoid the repeated threads to create bean, afterPrototypeCreation is to remove the logo. Scope is treated the same as the prototype bean.

GetObjectForBeanInstance method

And finally, there’s one method that I haven’t looked at, so let’s look at getobjectfor instance.

protected Object getObjectForBeanInstance(
      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {}
Copy the code

BeanInstance is the bean instance, name is the original bean name, which may contain the & prefix, beanName is the standard bean name, and MBD is the merged bean definition information.

/** Package-visible field for caching if the bean is a factory bean. */
@Nullable
volatile Boolean isFactoryBean;
Copy the code
// Determine if it is a factory bean
if (BeanFactoryUtils.isFactoryDereference(name)) {
   // If it is a NullBean, return it
   if (beanInstance instanceof NullBean) {
      return beanInstance;
   }
   // If it is not a FactoryBean type, throw an exception
   // is a FactoryBean, but not a FactoryBean type
   if(! (beanInstanceinstanceof FactoryBean)) {
      throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
   }
   // Set the isFactoryBean flag to indicate that the bean is a factory bean
   if(mbd ! =null) {
      mbd.isFactoryBean = true;
   }
   // Return the bean instance
   return beanInstance;
}
Copy the code

The factory bean is a simple bean that starts with & :

public static boolean isFactoryDereference(@Nullable String name) {
   return(name ! =null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
}
Copy the code

If the current bean instance is not of type FactoryBean, return it directly

// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if(! (beanInstanceinstanceof FactoryBean)) {
   return beanInstance;
}
Copy the code

If none of the above gets the bean instance, execute the following code:

/** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
Copy the code

Object object = null;
if(mbd ! =null) {
   mbd.isFactoryBean = true;
}
else {
   // Get the bean from the cache
   object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
   // Return bean instance from factory.FactoryBean<? > factory = (FactoryBean<? >) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.
   // If the bean definition is empty and the beanDefinitionMap contains the bean name, then the merged bean definition is obtained
   if (mbd == null && containsBeanDefinition(beanName)) {
      mbd = getMergedLocalBeanDefinition(beanName);
   }
   // Whether it is a user-defined bean
   booleansynthetic = (mbd ! =null && mbd.isSynthetic());
   // Get the bean from FactoryBeanobject = getObjectFromFactoryBean(factory, beanName, ! synthetic); }return object;
Copy the code

GetCachedObjectForFactoryBean method is simpler, can be obtained directly from the cache map:

@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
   return this.factoryBeanObjectCache.get(beanName);
}
Copy the code

Then there’s getObjectFromFactoryBean, which gets the object from the FactoryBean:

protected Object getObjectFromFactoryBean(FactoryBean<? > factory, String beanName,boolean shouldPostProcess)
Copy the code

Here we pass three parameters: Factory is the factoryBean passed above, beanName is the bean name defined in the configuration, shouldPostProcess means whether to allow post-processing of the bean.

if (factory.isSingleton() && containsSingleton(beanName)) {
  synchronized (getSingletonMutex()) {
   }
}
Copy the code

The first step is to determine whether the factory is a singleton and whether the collection of singleton beans contains the bean name. If so, execute the following code.

/** Cache of singleton objects created by FactoryBean: the object's FactoryBean name */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
Copy the code
// Get it from the cache first
Object object = this.factoryBeanObjectCache.get(beanName);
// If the cache does not exist, continue execution
if (object == null) {
   object = doGetObjectFromFactoryBean(factory, beanName);
   // Only post-process and store if not put there already during getObject() call above
   // (e.g. because of circular reference processing triggered by custom getBean calls)
   // Get the bean from the cache again, because the circular reference might cause the bean to already be in the cache
   Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
   // Get the value directly
   if(alreadyThere ! =null) {
      object = alreadyThere;
   }
   else {
      if (shouldPostProcess) {
          // The current bean is being created and returned directly without postprocessing
         if (isSingletonCurrentlyInCreation(beanName)) {
            // Temporarily return non-post-processed object, not storing it yet..
            return object;
         }
         // loop dependency check, record
         beforeSingletonCreation(beanName);
         try {
            // Do the post-processing on the bean
            object = postProcessObjectFromFactoryBean(object, beanName);
         }
         catch (Throwable ex) {
            throw new BeanCreationException(beanName,
                  "Post-processing of FactoryBean's singleton object failed", ex);
         }
         finally {
            // Loop dependency check, removeafterSingletonCreation(beanName); }}// Whether the current bean is in the collection of singleton beans, if so cache
      if (containsSingleton(beanName)) {
         this.factoryBeanObjectCache.put(beanName, object); }}}// Return the bean instance
return object;
Copy the code

And then there’s the else, which is less code, and there’s already the same code in if.

Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
   try {
      object = postProcessObjectFromFactoryBean(object, beanName);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex); }}return object;
Copy the code

DoGetObjectFromFactoryBean method:

private Object doGetObjectFromFactoryBean(FactoryBean
        factory, String beanName) throws BeanCreationException {
   Object object;
   try {
      // Verify permissions
      if(System.getSecurityManager() ! =null) {
         AccessControlContext acc = getAccessControlContext();
         try {
            object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
         }
         catch (PrivilegedActionException pae) {
            throwpae.getException(); }}else {
         // Here, the getObject method is called directlyobject = factory.getObject(); }}catch (FactoryBeanNotInitializedException ex) {
      throw new BeanCurrentlyInCreationException(beanName, ex.toString());
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
   }

   // Do not accept a null value for a FactoryBean that's not fully
   // initialized yet: Many FactoryBeans just return null then.
   if (object == null) {
      if (isSingletonCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(
               beanName, "FactoryBean which is currently in creation returned null from getObject");
      }
      object = new NullBean();
   }
   return object;
}
Copy the code

This part of the code gets the bean instance in getObject from the factoryBean.

Create instance flowchart

Below, according to the above source content, do a simple flow chart, easy to summarize and view:

Now that you’ve covered getBean, it’s time to actually create a bean instance. The article aims to record the learning content and share, if there is not enough, please forgive me, if there is a mistake in the article, but also hope big brother give advice, timely correction, common learning, common progress, mutual encouragement!