Proficiency in Spring Source | Bean Birth and Life Cycle

Keywords: Programming Spring Attribute github Java

I. Preface

In the last article, we ended the registration and scanning of beans. In this article, we will go into the instantiation and initialization of beans.

Source code analysis

Let's start with a mind map. Beans are instantiated and initialized mainly in the finishBean Factory Initialization (beanFactory); this is done in this method.

We can follow the mind map step by step, call getBean, doGetBean, in doGetBean will call getSingleton twice, we can see the first call.

Here we will first determine whether the first level cache singleton Object is empty, the first call is generally empty, and then determine whether isSingleton CurrentlyInCreation (beanName) is being created, mainly to determine whether there is a Bean name in the set of singletons CurrentlyInCreation, we can find that the previous has not gone to. This collection is added, so it will not be executed and return ed directly.

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   //Determine whether you are creating
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
         singletonObject = this.earlySingletonObjects.get(beanName);
         //
         if (singletonObject == null && allowEarlyReference) {
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               //
               singletonObject = singletonFactory.getObject();
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

If the first getSingleton can get a value that is not empty, the second getSingleton will not be executed.

Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
   if (logger.isDebugEnabled()) {
      if (isSingletonCurrentlyInCreation(beanName)) {
         logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
               "' that is not fully initialized yet - a consequence of a circular reference");
      }
      else {
         logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
      }
   }
   //Not equal to empty direct return
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

The second call to getSingleton, where we will create our beans, will execute five post processors nine times.

//The second call to getSingleton is not the same as the first call to getSingleton
// Create bean instance.
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);
}

1. The postProcessBeforeInstantiation method of InstantiationAwareBeanPostProcessors is called for the first time, which returns the type of Object before the object is instantiated. At this time, the object has not been instantiated. The return value of this method can replace the original object. If this method returns a value, Spring will only execute the postProcessAfterInitialization method of BeanPostProcessor and return directly to Bean. The following code will not execute, otherwise it will follow. Continue to follow the process.

try {
   //First call to the post processor
   //The bean instantiates the pre-and post-processor, and returns directly if the Bean returned by the post-process is not empty
   // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
   Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
   //If the bean is not empty, return directly
   if (bean != null) {
      return bean;
   }
}
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   //Are there any settings for before Instantiation Resolved?
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      //Determine whether InstantiationAwareBeanPostProcessors have been set
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            //applyBeanPostProcessorsBeforeInstantiation
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}

2. If the object returned in the previous step is empty, the following method will be executed.

The second call to the determineCandidate Constructors method of the post processor SmartInstantiationAwareBeanPostProcessor detects the construction method of the Bean and infers which construction method to instantiate.

//Create bean s
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {
   // Instantiate the bean.
   //Wrapper Packaging, bean Packaging
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
      instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
      //The second call to the post processor
      //Instantiate bean s to create objects
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		//Detecting the creation permission of a class, spring allows access to non-public classes by default
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		//If the factory method is not empty, then the factory method constructs the bean object
		//1. Creating objects through FactoryMethod
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
		//Shortcut can be used when building a bean many times
		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					//If the parameters of the construction method have been resolved, an example of a parametric construction method must be presented.
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				//2. Constructing Bean by Automatically Assembling Construction Method
				return autowireConstructor(beanName, mbd, null, null);
			} else {
				//3. By default parametric construction method
				return instantiateBean(beanName, mbd);
			}
		}

		//Second Execution Post Processor
		//It is up to the postprocessor to decide which constructions to return
		//Automated assembly model! = Automatic Assembly Technology
		//Five models, default NO, ignore directly???
		//AUTOWIRE_NO,AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE,AUTOWIRE_CONSTRUCTOR,AUTOWIRE_AUTODETECT
		//The model is NO, which is based on ByTe automatic assembly technology.
		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		// No special handling: simply use no-arg constructor.
		//Returning to null will use a parameterized construction method
		return instantiateBean(beanName, mbd);
	}
@Nullable
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
      throws BeansException {

   //
   if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            //By which construction methods to instantiate objects
            Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
            if (ctors != null) {
               return ctors;
            }
         }
      }
   }
   return null;
}

3. Call the postProcessMergedBeanDefinition method of the postProcessor MergedBeanDefinition PostProcessor for the third time to find and cache the annotation information of the object.

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
   if (!mbd.postProcessed) {
      try {
         //The third call to the post processor
         //Execute post processor
         applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
      } catch (Throwable ex) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
               "Post-processing of merged bean definition failed", ex);
      }
      mbd.postProcessed = true;
   }
}
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof MergedBeanDefinitionPostProcessor) {
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

4. Call SmartInstantiationAwareBeanPostProcessor's getEarlyBeanReference method for the fourth time to expose the object in advance.

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
      isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
   if (logger.isDebugEnabled()) {
      logger.debug("Eagerly caching bean '" + beanName +
            "' to allow for resolving potential circular references");
   }
   //The fourth call to the post processor
   //GettEarlyBeanReference to Get Early Exposure Objects
   //Four sets of Map s
   addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
            exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
         }
      }
   }
   return exposedObject;
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      //
      if (!this.singletonObjects.containsKey(beanName)) {
         this.singletonFactories.put(beanName, singletonFactory);
         //
         this.earlySingletonObjects.remove(beanName);
         //All created objects
         this.registeredSingletons.add(beanName);
      }
   }
}

This will determine whether there are objects in the first-level cache singleton Objects or not. If not, it will be placed in the third-level cache singleton Factories, which is also the core of Spring's solution to cyclic dependencies.

//Fifth, six calls to the post processor
//Assigning attributes to complete automatic assembly
populateBean(beanName, mbd, instanceWrapper);

5. The fifth call to the postProcessAfterInstantiation method of the post processor InstantiationAwareBeanPostProcessor, which is called after the object is instantiated. At this time, the object has been instantiated, but the attribute of the object has not been set. If the method returns the false amount, the attribute value will be ignored. If true is returned, the properties will be set according to the normal process.

//spring is not required to set properties
boolean continueWithPropertyPopulation = true;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         //Fifth Execution Post Processor
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         //InstantiationAwareBeanPostProcessor implements this interface and returns the bean, spring will think that no properties need to be set
         if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            continueWithPropertyPopulation = false;
            break;
         }
      }
   }
}

6. For the sixth time, we call the postProcessProperty Values method of InstantiationAwareBeanPostProcessor to fill in the attributes and complete the automatic injection. We can also modify the attributes that should be set. If postProcessAfterInstantiation returns false, this method will not be called.

if (hasInstAwareBpps) {
   for (BeanPostProcessor bp : getBeanPostProcessors()) {
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
         //Sixth Execution Post Processor
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         //Automatically assemble, complete injection
         pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
         if (pvs == null) {
            return;
         }
      }
   }
}
//Seventh and eighth, initialization
exposedObject = initializeBean(beanName, exposedObject, mbd);
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   } else {

      invokeAwareMethods(beanName, bean);
   }
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      //BeanPostProcessors Before
      //Seventh Execution Post Processor Executes before
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
   try {
      //Executing bean lifecycle callback init method
      invokeInitMethods(beanName, wrappedBean, mbd);
   } catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      //The eighth time the post processor is executed and the post processor after method is executed
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

7. The seventh call to the postProcessBeforeInitialization method of the postprocessor BeanPostProcessor

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

8. The eighth call to the postProcessAfterInitialization method of the postprocessor BeanPostProcessor.

@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {

   Object result = existingBean;
   //The eighth call to the post processor
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

BeanPostProcessor is an extension point of Spring. By implementing BeanPostProcessor, we can achieve the following functions:

1. Programmers can intervene in the instantiation process of beans, thus reducing the burden of Bean factories.
2. Execution after instantiation, that is, when an Object is new from the bean Definition and the bean PostProcessor intervenes, it will be placed in the container.
3. Defining a class implements BeanPostProcessor, which by default handles all bean s in the entire Spring container.
4. This interface can be implemented by multiple classes, forming a list and executing in turn.

Finally, add a general mind map.

III. CONCLUSION

Finally, let's sum up again.

First of all, after scanning and registering a Bean, we will start the instantiation and initialization of a Bean. Instantiation and initialization are two different concepts. Instantiation is simply to give a Bean to new, without setting the initial value. Initialization is to create an available Bean completely. Come out. The process of instantiation and initialization is as follows:

First we call getBean. After doGetBean, we call two getSingleton methods. Then in the second getSingleton, we call five post processors eight times to instantiate and initialize beans.

1. Call the postProcessBeforeInstantiation method of InstantiationAwareBeanPostProcessors, which inherits BeanPostProcessor and provides three methods internally, plus two methods of BeanPostProcessor, a total of five methods. The postProcessBeforeInstantiation method is called before the target object is instantiated. This method can return any value. At this time, the target object has not been instantiated, so this return value can replace the object that should be returned. If this method returns a value, then only BeanPostPro will be called. Cessor's postProcessAfterInitialization method, other steps are no longer executed, otherwise, it will follow the normal process.

2. Call the determineCandidate Constructors method of Smart InstantiationAware Bean PostProcessor. This method mainly infers the construction method, and then instantiates the beans. If not inferred, the default construction method will be used to complete the instantiation of beans.

3. Call the postProcessMergedBeanDefinition method of MergedBeanDefinitionPostProcessor to cache the Bean's annotation information, but no injection has been made at this time. Injection is another post-processing thing.

4. Call SmartInstantiationAwareBeanPostProcessor's getEarlyBeanReference method to expose beans in advance, mainly to solve the problem of circular reference.

5. Call the postProcessAfterInstantiation method of InstantiationAwareBeanPostProcessor, which is called after the target method is instantiated. At this time, the object has been instantiated, but the attribute has not been set. If the method returns false, the setting of the attribute will be ignored. If the method returns true, the normal flow will follow. Cheng Ke.

6. Call the postProcessPropertyValues method of InstantiationAwareBeanPostProcessor to assign and modify attributes. If the value returned by postProcessAfterInstantiation is false, the method will not execute.

7,8. Call BeanPostProcessor's postProcessBeforeInitialization method and postProcessAfterInitialization method, between which callbacks to the declaration cycle are also executed.

In order to show the calling process of source code more intuitively, I drew a mind map!
In order to show the calling process of source code more intuitively, I drew a mind map!
In order to show the calling process of source code more intuitively, I drew a mind map!

The Birth of Spring Bean and Its Life Cycle Mind Map

My Github: Github
CSDN: CSDN
Personal website: sirius blog
E-mail: 1136513099@qq.com

Recommended reading
The most complete and perfect summary of the mind map of JAVA technology system in history, none of them!

Posted by adren on Tue, 20 Aug 2019 06:51:57 -0700