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.