Bean life cycle

Keywords: Java Spring Back-end

The life cycle of a Bean can be divided into four steps

  • Bean instantiation
  • Bean attribute assignment
  • Bean initialization
  • Destroy

In traditional Java applications, the life cycle of a Bean is very simple. Instantiate a Bean using the Java keyword new, and then the Bean can be used. Once the Bean is no longer used, Java automatically garbage collects it. The life cycle of Spring managed beans is much more complex. The life cycle of beans is still a hot issue in Spring interview.
The following is an approximate bean life cycle flow chart drawn according to the source code. The main logic of the bean life cycle is in the doCreateBean() method of the AbstractAutowireCapableBeanFactory class. Bean instantiation, attribute assignment and initialization are executed in order

When instantiating a Bean, appropriate instantiation methods will be selected according to conditions, such as factory method, instantiation of structure with parameters and instantiation of structure without parameters,

    // Partial source code
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		if (instanceWrapper == null) {
			//Create bean instantiation and use appropriate instantiation strategies to create new instances: factory methods, automatic constructor injection, and simple initialization..
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
     }

Enter the method of creating Bean instance and call the required instantiation strategy

    // Part of the source code in createbean instance
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		//Resolve the class object of the current bean from the bean definition
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		/**
		 * This method is newly added in spring 5.0. If there is a Supplier callback, the given callback method is used to initialize the policy
		 */
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		/**
		 * Factory method. If we configure it through the configuration class, the factory method is adopted, and the method name is tulingDao, which is the name of our factory method
		 * @Bean The instance is created here
		 */
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
		//If parsed
		if (resolved) {
			if (autowireNecessary) {
				//Reflection call through a constructor with parameters
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//Call the parameterless constructor to create the object
				return instantiateBean(beanName, mbd);
			}
		}

		/**
		 * Select the appropriate constructor object through the bean's post processor
		 */
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		/**
		 *  If the BeanPostProcessor is customized, the constructor or
		 *  Automatic assembly mode using constructor or
		 *  The BeanDefinition constructor parameter is set, or
		 *  There are parameters: args in getBean(String name, Object... args)
		 *  Is initialized with a custom constructor
		 */
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			//Creating objects through constructors
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		//Creates an object using a parameterless constructor call
		return instantiateBean(beanName, mbd);
	}

Assign the attribute after the Bean is instantiated, and call populateBean(beanName, mbd, instanceWrapper); Method for attribute assignment and attribute injection according to different methods

// Partial source code
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		/**
		 * Determine the attribute injection model of our bean
		 * AUTOWIRE_BY_NAME Inject by name
		 * AUTOWIRE_BY_TYPE Injection according to type
		 */

		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
			//Encapsulate PropertyValues into MutablePropertyValues
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			//Inject according to the attribute name of the bean
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			//Inject according to the type of bean
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			//Overwrite the processed attributes with the original ones
			pvs = newPvs;
		}
}

After attribute injection, initializeBean(beanName, exposedObject, mbd) is called. Method to initialize the Bean.

	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 {
			//If our bean implements the XXXAware interface, we can call back the method
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			//Call the postProcessorsBeforeInitialization method of our bean's post processor  
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			//Call initialization 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()) {
			//Call the PostProcessorsAfterInitialization method of our bean's postprocessor
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

Looking at the source code, we can find that invokeawaremethods (bean name, bean) will be called before calling the real initialization method; To detect whether the XXXAware interface is implemented
Step: call setBeanName method of BeanNameAware interface, call setBeanClassLoader method of BeanClassLoaderAware, call setBeanFactory method of beanfactory aware, and the source code is as follows

	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			//Our bean implements BeanNameAware
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			//The BeanClassLoaderAware interface is implemented
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			//Beanfactory aware is implemented
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

Call your own initialization method

	protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		//Determine whether the InitializingBean interface is implemented in our container
		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isDebugEnabled()) {
				logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//Callback the afterpropertieset() method of InitializingBean
				((InitializingBean) bean).afterPropertiesSet();
			}
		}

		// Call initMethod
		if (mbd != null && bean.getClass() != NullBean.class) {
			//Let's see if there is an init method defined in beanclass
			String initMethodName = mbd.getInitMethodName();
			//Judge whether the custom init method name is not called afterpropertieset
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				//Call our own initialization method
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

After the bean is instantiated, it will call the PostProcessorsAfterInitialization method of the post processor of our bean. When this method is executed, it will create a proxy object for the class that needs a proxy, that is, AOP proxy

		if (mbd == null || !mbd.isSynthetic()) {
			//Call the PostProcessorsAfterInitialization method of our bean's postprocessor
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		//Get the post processor of all bean s in our container
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			/**
			 *
			 * What is implemented here is the postProcessAfterInitialization of the BeanPostProcessor interface to generate our proxy object
			 */
			Object current = processor.postProcessAfterInitialization(result, beanName);
			//If only one of them returns null, the original is returned directly
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

After Bean initialization, it can be used.

summary

  1. When Spring starts, find the beans that need to be managed by Spring for instantiation
  2. After instantiation, inject attributes into the Bean
  3. If the Bean implements the BeanNameAware interface, Spring passes the Id of the Bean to the setBeanName() method
  4. If the Bean implements the BeanClassLoaderAware interface, Spring will call the setBeanClassLoader() method
  5. If the Bean implements the BeanFactory aware interface, Spring will call the setBeanFactory() method to pass in the BeanFactory container instance
  6. If beans implement the BeanPostProcessor interface, Spring will call their postProcessBeforeInitialization() method
  7. If beans implement the InitializingBean interface, Spring will call their afterpropertieset () method
  8. If beans implement the BeanPostProcessor interface, Spring will call their postProcessAfterInitialization() method
  9. If the bean implements the DisposableBean interface, Spring will call its destroy () interface method. Similarly, if the bean uses the destroy method declaration, the method will also be called

Posted by IsmAvatar on Mon, 01 Nov 2021 09:00:20 -0700