Unveiling Spring's Bean Lifecycle: From Retrieval to Destruction

This article provides a comprehensive, step‑by‑step walkthrough of Spring's Bean lifecycle—including bean retrieval, creation, property population, initialization, and destruction—illustrated with flowcharts and complete Java code snippets to help developers understand the inner workings of the framework.

Programmer DD
Programmer DD
Programmer DD
Unveiling Spring's Bean Lifecycle: From Retrieval to Destruction

1. Retrieving a Bean

The entry point for bean retrieval is the doGetBean method in AbstractBeanFactory. The process includes handling bean names that start with "&" (indicating a FactoryBean), checking the singleton cache, dealing with circular dependencies, and delegating to parent factories if necessary.

2. Creating a Bean

2.1 Before Instantiation

The method createBean in AbstractAutowireCapableBeanFactory performs several checks: it resolves the bean class, verifies visibility, and determines whether to apply InstantiationAwareBeanPostProcessor callbacks such as postProcessBeforeInstantiation and postProcessAfterInitialization. If these callbacks return a non‑null bean, the standard creation flow is short‑circuited.

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // condition 1
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // condition 2 & 3
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
                bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
        }
    }
    return bean;
}

2.2 Actual Bean Creation (doCreateBean)

The doCreateBean method orchestrates the full creation process: it checks for an existing instance wrapper, creates the bean instance (via constructors or factory methods), resolves constructor arguments, applies post‑processors, and finally populates properties.

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // Resolve bean class
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    if (beanClass == null) {
        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non‑public access not allowed: " + beanClass.getName());
    }
    // Use supplier if available
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    // Factory method handling
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // Constructor resolution and autowiring
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }
    // Default no‑arg constructor
    return instantiateBean(beanName, mbd);
}

2.3 Populating Bean Properties

The populateBean method applies property values, handling autowire‑by‑name and autowire‑by‑type, and invoking InstantiationAwareBeanPostProcessor callbacks for property processing.

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        return;
    }
    // Apply InstantiationAwareBeanPostProcessors before property population
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }
    // Resolve property values, autowire by name/type, and apply them
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    // ... (autowire and apply property values) ...
    applyPropertyValues(beanName, mbd, bw, pvs);
}

2.4 Initializing the Bean

During initialization, Spring invokes aware‑interface methods ( BeanNameAware, BeanFactoryAware, etc.), BeanPostProcessor callbacks ( postProcessBeforeInitialization, postProcessAfterInitialization), and the bean's own afterPropertiesSet method if it implements InitializingBean.

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // Aware interfaces
    if (bean instanceof BeanNameAware) {
        ((BeanNameAware) bean).setBeanName(beanName);
    }
    // ... other aware interfaces ...
    // BeanPostProcessor before initialization
    Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    // Invoke custom init methods
    if (bean instanceof InitializingBean) {
        ((InitializingBean) bean).afterPropertiesSet();
    }
    // Custom init-method
    String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
    if (StringUtils.hasLength(initMethodName) && !(bean instanceof InitializingBean && "afterPropertiesSet".equals(initMethodName))) {
        invokeCustomInitMethod(beanName, bean, mbd);
    }
    // BeanPostProcessor after initialization
    return applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

3. Destroy Method and Bean Destruction

When a bean is destroyed, Spring checks for a configured destroyMethodName or a DestructionAwareBeanPostProcessor. It registers a DisposableBeanAdapter that will invoke the appropriate destroy callbacks.

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    String destroyMethodName = inferDestroyMethodIfNecessary(bean, mbd);
    if (destroyMethodName != null && !(bean instanceof DisposableBean && "destroy".equals(destroyMethodName))) {
        if (!mbd.isExternallyManagedDestroyMethod(destroyMethodName)) {
            DisposableBeanAdapter adapter = new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc);
            registerDisposableBean(beanName, adapter);
        }
    }
}

The DisposableBeanAdapter implements Runnable and, when executed, calls the bean's destroy method (either via DisposableBean or a custom destroy method) while handling security contexts and logging.

public class DisposableBeanAdapter implements Runnable {
    private final Object bean;
    private final String beanName;
    private final boolean invokeDisposableBean;
    private final AccessControlContext acc;
    // constructor omitted for brevity
    @Override
    public void run() {
        if (invokeDisposableBean) {
            ((DisposableBean) bean).destroy();
        } else {
            // invoke custom destroy method via reflection
        }
    }
}

4. Summary

The article walks through the entire Spring Bean lifecycle with detailed flowcharts: preparation before instantiation, the actual creation steps, property population, initialization callbacks, and finally destruction handling. Each stage is backed by concrete code excerpts from the Spring framework, providing a clear map for developers to follow.

Images

Spring Bean lifecycle overview
Spring Bean lifecycle overview
Get Bean step
Get Bean step
Create Bean step
Create Bean step
doCreateBean method
doCreateBean method
populateBean
populateBean
initializeBean
initializeBean
destroyBean
destroyBean
Overall lifecycle diagram
Overall lifecycle diagram
Pre‑instantiation preparation
Pre‑instantiation preparation
Before instantiation
Before instantiation
After instantiation
After instantiation
Before initialization
Before initialization
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javadependency-injectionSpring Frameworkbean-lifecycle
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.