preface

The Spring Bean lifecycle is a common interview question and a technical point often used in daily development. In application development, you often need to perform special initialization work, such as establishing a database connection, opening a network connection, or in some business beans, you want to get the Spring IOC container, Or maybe you want to get some beans that are already instantiated. At the same time, there is some destruction that needs to be done at the end of the service. For working design purposes, Spring IOC provides interfaces that allow application initialization and destruction of custom beans.

Spring Bean life cycle

Take a look at the Spring Bean lifecycle flowchart for subsequent source code analysis.The Spring Bean lifecycle is divided into four processes at large nodes:Instantiate, attribute assignment, initialize, destroy. The two points we should cover most in our daily business development areInitialization and destruction, such as the custom Bean implementation InitializingBean, DisposeableBean.

Source code analysis

The Spring IOC container is initialized

Initialization from AbstractAutowireCapableBeanFactory doCreateBean method start, I marked the key points in the corresponding code position

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
	BeanWrapper instanceWrapper = null;
	if (mbd.isSingleton()) {
		instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
	}
    
	//1. Bean instantiation
	if (instanceWrapper == null) {
	   instanceWrapper = this.createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<? > beanType = instanceWrapper.getWrappedClass();if(beanType ! = NullBean.class) { mbd.resolvedTargetType = beanType; }synchronized(mbd.postProcessingLock) {
		if(! mbd.postProcessed) {try {
				this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
			} catch (Throwable var17) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
			}

			mbd.postProcessed = true; }}boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
	if (earlySingletonExposure) {
		this.addSingletonFactory(beanName, () -> {
			return this.getEarlyBeanReference(beanName, mbd, bean);
		});
	}

	Object exposedObject = bean;

	try {
	    //2. Attribute assignment
       this.populateBean(beanName, mbd, instanceWrapper);
	    / / 3. Initialization
	    exposedObject = this.initializeBean(beanName, exposedObject, mbd);
	} catch (Throwable var18) {
	    if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
		throw (BeanCreationException)var18;
	    }

	    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
	}

	if (earlySingletonExposure) {
		Object earlySingletonReference = this.getSingleton(beanName, false);
		if(earlySingletonReference ! =null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			} else if (!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
				String[] dependentBeans = this.getDependentBeans(beanName);
				Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
				String[] var12 = dependentBeans;
				int var13 = dependentBeans.length;

				for(int var14 = 0; var14 < var13; ++var14) {
					String dependentBean = var12[var14];
					if (!this.removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); }}if(! actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned  off, for example."); }}}}try {
	    //4. Destroy - Register callback interface
	    this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
	    return exposedObject;
	} catch (BeanDefinitionValidationException var16) {
	    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16); }}Copy the code

To keep the code snippet clean, I removed the Logger code.

As you can see from the code snippet above, the four key points in the late life of Spring that we summarized above are reflected in our analysis of the initialization and destruction processes.

AbstractAutowireCapableBeanFactory.initializeBean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	//1. Check Aware related interfaces and set dependencies
    //BeanNameAware, BeanClassLoaderAware, BeanFactoryAware
	if(System.getSecurityManager() ! =null) {
		AccessController.doPrivileged(() -> {
			this.invokeAwareMethods(beanName, bean);
			return null;
		}, this.getAccessControlContext());
	} else {
		this.invokeAwareMethods(beanName, bean);
	}

    //2.BeanPostProcessor preprocessing
	Object wrappedBean = bean;
	if (mbd == null| |! mbd.isSynthetic()) {/ / the BeanPostProcessor interface postProcessBeforeInitialization callback
		wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
	}
    
	AfterPropertiesSet () if InitializingBean interface is implemented
	//4. If user-defined init-method() is configured, run this command.
	try {
		this.invokeInitMethods(beanName, wrappedBean, mbd);
	} catch (Throwable var6) {
		throw newBeanCreationException(mbd ! =null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
	}

    //5.BeanPostProcessor
	if (mbd == null| |! mbd.isSynthetic()) {/ / the BeanPostProcessor interface postProcessAfterInitialization callback
		wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}
Copy the code

AbstractAutowireCapableBeanFactory. InvokeAwareMethods invokeAwareMethod is called the interface at the end of a series of Aware, Examples include BeanNameAware, ApplicationContextAware, and BeanFactoryAware.

private void invokeAwareMethods(String beanName, Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof BeanNameAware) {
         ((BeanNameAware)bean).setBeanName(beanName);
      }

       if (bean instanceof BeanClassLoaderAware) {
           ClassLoader bcl = this.getBeanClassLoader();
           if(bcl ! =null) { ((BeanClassLoaderAware)bean).setBeanClassLoader(bcl); }}if (bean instanceof BeanFactoryAware) {
           ((BeanFactoryAware)bean).setBeanFactory(this); }}}Copy the code

AbstractAutowireCapableBeanFactory. InvokeInitMethods invokeInitMethods is called the afterPropertiesSet InitializingBean interface, And check for custom init-method.

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
	boolean isInitializingBean = bean instanceof InitializingBean;
	if (isInitializingBean && (mbd == null| |! mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		if(System.getSecurityManager() ! =null) {
			try {
				AccessController.doPrivileged(() -> {
					((InitializingBean)bean).afterPropertiesSet();
					return null;
				}, this.getAccessControlContext());
			} catch (PrivilegedActionException var6) {
				throwvar6.getException(); }}else{ ((InitializingBean)bean).afterPropertiesSet(); }}if(mbd ! =null&& bean.getClass() ! = NullBean.class) { String initMethodName = mbd.getInitMethodName();if(StringUtils.hasLength(initMethodName) && (! isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && ! mbd.isExternallyManagedInitMethod(initMethodName)) {this.invokeCustomInitMethod(beanName, bean, mbd); }}}Copy the code

The Spring IOC container creates beans by instantiating them, destroying them, and implementing BeanPostProcessor interface methods. Let’s look at the Spring container destruction phase.

Container to destroy

The Spring container destroys the procedure call chain Spring uses adapter mode here, which means the final destruction task is taken care of by the DisposableBeanAdapter. Let’s take a look at the structure of the DisposeableBeanAdapter.You can see from the structure that the bean property type is Object, which is the bean to be destroyed, and the beanName property.

public void destroy(a) {
    if(! CollectionUtils.isEmpty(this.beanPostProcessors)) {
        Iterator var1 = this.beanPostProcessors.iterator();

        while(var1.hasNext()) {
            DestructionAwareBeanPostProcessor processor = (DestructionAwareBeanPostProcessor)var1.next();
            processor.postProcessBeforeDestruction(this.bean, this.beanName); }}if (this.invokeDisposableBean) {
		try {
			if(System.getSecurityManager() ! =null) {
				AccessController.doPrivileged(() -> {
					((DisposableBean)this.bean).destroy();
					return null;
				}, this.acc);
			} else {
				((DisposableBean)this.bean).destroy(); }}catch (Throwable var3) {
			
		}
	}

	if (this.destroyMethod ! =null) {
		this.invokeCustomDestroyMethod(this.destroyMethod);
	} else if (this.destroyMethodName ! =null) {
		Method methodToInvoke = this.determineDestroyMethod(this.destroyMethodName);
		if(methodToInvoke ! =null) {
			this.invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke)); }}}Copy the code

conclusion

The Spring Bean life cycle is divided into four phases and multiple extension points, which are divided into affecting multiple beans and individual beans. There are four stages: instantiation, attribute assignment, initialization, and destruction. Extension points affect multiple beans

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

Affecting individual beans

  • BeanNameAware
  • BeanFactoryAware
  • BeanClassLoaderAware
  • ApplicationContextAware

Two key interfaces in the Spring lifecycle: InitialzingBean, DisposableBean.