Spring IOC – Bean life cycle instantiation

As mentioned in the Spring startup process article, the initialization of the container starts with the refresh method, which calls the finishBeanFactoryInitialization method during the initialization process.

In this method, the DefaultListableBeanFactory#preInstantiateSingletons method will be called. The core function of this method is to initialize non-lazy-loaded beans, and provides two extension points. The source code and comments are as follows:

@Override
public void preInstantiateSingletons() throws BeansException {

   //This method first copies a list of BeanDefinition names. In order to prevent new BeanDefinitions from being registered during the initialization process,
   //This leads to concurrent modification exceptions during the traversal process
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   //For each non-abstract, singleton and non-lazy-loaded BeanDefinition, if it is a FactoryBean,
   //Get the instance of FactoryBean, if FactoryBean implements the `SmartFactoryBean` interface,
   //Then call the `isEagerInit` method to determine whether pre-instantiation is required. The default is that pre-instantiation is required.
   //If the Bean needs to be instantiated in advance, call the `getBean` method to instantiate it.
   for (String beanName : beanNames) {
      RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      // Not an abstract class & amp; & amp; It’s a singleton & amp; & amp; It’s not lazy loading
      if (!bd.isAbstract() & amp; & amp; bd.isSingleton() & amp; & amp; !bd.isLazyInit()) {
         if (isFactoryBean(beanName)) {
            Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
            if (bean instanceof FactoryBean) {
               FactoryBean<?> factory = (FactoryBean<?>) bean;
               boolean isEagerInit;
               if (System.getSecurityManager() != null & amp; & amp; factory instanceof SmartFactoryBean) {
                  isEagerInit = AccessController.doPrivileged(
                        (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                        getAccessControlContext());
               }
               else {
                  isEagerInit = (factory instanceof SmartFactoryBean & amp; & amp;
                        ((SmartFactoryBean<?>) factory).isEagerInit());
               }
               if (isEagerInit) {
                  getBean(beanName);
               }
            }
         }
         else {
            // Here is the formal initialization of the ordinary singleton Bean
            getBean(beanName);
         }
      }
   }

   //For each singleton Bean that implements the SmartInitializingSingleton interface, call its afterSingletonsInstantiated method
   //The execution time is at the end of the bean's life cycle, that is, after the bean completes instantiation, attribute injection, and related initialization operations.
   for (String beanName : beanNames) {
      Object singletonInstance = getSingleton(beanName);
      if (singletonInstance instanceof SmartInitializingSingleton) {
         SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
         if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
               smartSingleton.afterSingletonsInstantiated();
               return null;
            }, getAccessControlContext());
         }
         else {
            // For example: ScheduledAnnotationBeanPostProcessor CacheAspectSupport MBeanExporter, etc.
            smartSingleton.afterSingletonsInstantiated();
         }
      }
   }
}

This method can be briefly summarized as the following three points:

  1. For subclasses that implement SmartFactoryBean, if isEagerInit (immediate initialization) returns true, the getObject object that is lazy loaded will be initialized immediately;

  2. Otherwise, call the getBean method normally to start the bean life cycle;

  3. After the bean life cycle processing is completed, call the afterSingletonsInstantiated method of the singleton Bean that implements the SmartInitializingSingleton interface.

Continuing is the method of “doing real things”: AbstractBeanFactory#doGetBean. The logic flow chart is as follows:

The core method of creating Bean is AbstractAutowireCapableBeanFactory#createBean. The source code and comments are as follows:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
   RootBeanDefinition mbdToUse = mbd;
   
   //Make sure the bean Class type is actually resolved
   //And clone the beanDefinition in case of dynamically resolved classes, because dynamically resolved classes cannot be stored in the shared merged beanDefinition
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null & amp; & amp; !mbd.hasBeanClass() & amp; & amp; mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
   // Pre-mark methods without overloads to avoid the overhead of parameter type checking
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // Pre-instantiation phase: Give BeanPostProcessors the opportunity to return the proxy instead of the target bean instance
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
      //Create a bean that actually "does real work"
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

Before actual instantiation, if the bean implements the InstantiationAwareBeanPostProcessor interface, its postProcessBeforeInstantiation method will be called. This is the pre-instantiation stage of the bean life cycle. The core methods and functions provided by this interface are shown in the following table:

Method name

Action stage

Function

postProcessBeforeInstantiation

Before instantiation

This method passes in the target Bean type and BeanName; this method can return an object of the Bean type, or a proxy object for the Bean; when this method returns the instantiated object, all subsequent Bean instantiation and initialization actions will no longer be conducted. Only the subsequent BeanPostProcessor#postProcessAfterInitialization method will be called

postProcessAfterInstantiation

After instantiation

This method passes in the Bean object and BeanName that have not yet been assembled with attributes. If this method returns false, subsequent attribute assembly actions will be skipped. Generally, true should be returned.

postProcessProperties

After instantiation

Before attribute filling

This method passes in the PropertyValues and BeanName configured during configuration. The PropertyValues returned by this method will eventually be assembled into the Bean object.

Next is the doCreateBean method, whose logic flow chart is as follows:

  1. First check whether the instanceWrapper variable is null. It is usually null here, unless the bean currently being created exists in factoryBeanInstanceCache. This is a collection of FactoryBeans that have not yet been created.

  2. Call the createBeanInstance method to instantiate the Bean. This method will be explained later.

  3. If the current RootBeanDefinition object has not called the method of the implemented MergedBeanDefinitionPostProcessor interface, it will be called

  4. When the following three points are met (1) it is a singleton Bean (2) trying to resolve circular references between beans (3) the bean is currently being created, it will further check whether the SmartInstantiationAwareBeanPostProcessor interface is implemented and if it is implemented Then call the implemented getEarlyBeanReference method

  5. Call the populateBean method to populate attributes

  6. Call the initializeBean method to initialize the Bean

The source code and comments of the key method AbstractAutowireCapableBeanFactory#createBeanInstance are as follows:

 // Create a new instance of the specified bean using the appropriate instantiation strategy: factory method, constructor autowiring or simple instantiation
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // Make sure bean class is actually resolved at this point.
   // Get the Class object of the bean
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null & amp; & amp; !Modifier.isPublic(beanClass.getModifiers()) & amp; & amp; !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }

   // Get an object through the instanceSupplier provided in bd
   // Normal bd does not have this instanceSupplier attribute. This is also an extension point provided by Spring, but it is not commonly used in practice.
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // If the factory method is not null, use the factory method initialization strategy
   // The factoryMethodsName attribute is provided in bd, so use the factory method to create the object
   //The factory method will distinguish between static factory method and instance factory method.
   if (mbd.getFactoryMethodName() != null) {
      // If a factory method is used, call the factory method to create a bean instance. Instances created by @Bean annotation will enter here
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   // In prototype mode, if the Bean has been created once, there is no need to infer the constructor again.
   // Whether the constructor has been inferred
   boolean resolved = false;
   // Whether the constructor needs to be injected
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         // There are multiple constructors in a class, and each constructor has different parameters, so the call needs to be locked based on the parameters before calling.
         // Constructor or factory method
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   // If it has been parsed, use the parsed constructor method without locking again.
   if (resolved) {
      if (autowireNecessary) {
         // Constructor automatic injection
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // Construct using default constructor
         return instantiateBean(beanName, mbd);
      }
   }

   // Candidate constructors for autowiring?
   // Need to parse the constructor according to parameters
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      // Constructor automatic injection
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // Preferred constructors for default construction?
   // Get the preferred constructor as the default constructor
   ctors = mbd.getPreferredConstructors();
   if (ctors != null) {
      return autowireConstructor(beanName, mbd, ctors, null);
   }

   // No special handling: simply use no-arg constructor.
   // No special processing: simply use the no-argument constructor
   return instantiateBean(beanName, mbd);
}

Summarized as follows:

  1. First check whether the Class is associated and whether the corresponding modifier is public

  2. If the user defines a function for Bean instantiation, it is called and returned

  3. If the current Bean implements the FactoryBean interface, call the getObject method of the corresponding FactoryBean interface.

  4. Processed according to whether the construction parameters are passed in when getBean

  • 4.1 If no construction parameters are passed in, check whether there is a cached parameterless constructor. If there is, use the constructor to create it directly. If not, the instantiateBean method will be called to obtain the instantiated strategy first. The default is CglibSubclassingInstantiationStrategy, and then instantiate the Bean. finally return

  • 4.2 If the construction parameters are passed in, it will first check whether the SmartInstantiationAwareBeanPostProcessor interface is implemented. If it is implemented, determineCandidateConstructors will be called to obtain the returned candidate constructor.

  • 4.3 Check whether the four conditions are met: (1) the constructor is not null, (2) the associated injection method obtained from the RootBeanDefinition is constructor injection (if there are no construction parameters, it is setter injection, if there are, it is constructor injection) ( 3) Contains construction parameters (4) If the construction parameters passed in by the getBean method are not empty and satisfy one of them, the returned candidate constructor will be called to instantiate the Bean and returned. If neither is satisfied, the appropriate parameterized constructor will be selected based on the construction parameters. The provider then instantiates the Bean and returns

  • If there is no suitable constructor above, use the parameterless constructor directly to create and return the Bean.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 139421 people are learning the system