Understanding Spring Bean Lifecycle: Flowcharts and Code Walkthrough

This article explains the complete Spring Bean lifecycle—from bean retrieval, through creation, property population, initialization, and destruction—using detailed flowcharts, step‑by‑step descriptions, and full source code snippets to illustrate each phase.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Understanding Spring Bean Lifecycle: Flowcharts and Code Walkthrough

1. Getting a Bean

The entry point is the AbstractBeanFactory.doGetBean method. It first handles bean names (e.g., names starting with "&" refer to FactoryBean objects), then checks the singleton cache. If a singleton exists and is not currently being created, it returns the cached instance; otherwise it proceeds to resolve circular dependencies and may delegate to a parent BeanFactory before creating the bean.

2. Creating a Bean

2.1 Pre‑creation checks

The logic resides in AbstractAutowireCapableBeanFactory.createBean. It first obtains the bean class from the RootBeanDefinition and evaluates three conditions:

Whether beforeInstantiationResolved is true.

Whether the bean is a native (non‑synthetic) bean.

Whether the bean has InstantiationAwareBeanPostProcessor support.

If all three are satisfied, Spring invokes the postProcessBeforeInstantiation method of any registered InstantiationAwareBeanPostProcessor. If a non‑null bean is returned, postProcessAfterInitialization is also called.

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()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

2.2 Actual bean creation (doCreateBean)

The doCreateBean method orchestrates the full creation process, including instance creation, property population, and initialization.

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // step 1: resolve bean class
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    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());
    }
    // step 2: supplier
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
        return obtainFromSupplier(instanceSupplier, beanName);
    }
    // step 3: factory method
    if (mbd.getFactoryMethodName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    // step 4: constructor selection and autowiring
    if (resolved && autowireNecessary) {
        return autowireConstructor(beanName, mbd, null, null);
    } else {
        return instantiateBean(beanName, mbd);
    }
}

2.3 Property population (populateBean)

After instantiation, Spring populates bean properties, applies InstantiationAwareBeanPostProcessor callbacks, performs dependency checks, and finally applies the resolved property values.

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;
    }
    boolean continueWithPropertyPopulation = true;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    if (!continueWithPropertyPopulation) {
        return;
    }
    // Resolve autowiring by name/type, apply property values, etc.
    // ... (omitted for brevity) ...
    applyPropertyValues(beanName, mbd, bw, pvs);
}

2.4 Initialization (initializeBean)

Spring invokes aware‑interface callbacks (e.g., BeanNameAware, ApplicationContextAware), then runs BeanPostProcessor.postProcessBeforeInitialization, the bean’s own afterPropertiesSet (if it implements InitializingBean) or a custom init‑method, followed by postProcessAfterInitialization.

3. Destruction

When the container shuts down, Spring checks for a configured destroyMethodName or a DisposableBean implementation. It registers a DisposableBeanAdapter that invokes the appropriate destroy callbacks.

protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
    // ...
    new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc);
    // ...
}
public void destroy() {
    if (this.invokeDisposableBean) {
        try {
            ((DisposableBean) this.bean).destroy();
        } catch (Throwable ex) {
            // log warning
        }
    }
    // invoke custom destroy method if present
}

4. Summary

The article presents a complete, step‑by‑step illustration of the Spring Bean lifecycle, from retrieval to destruction, supplemented by flowcharts and the essential source code of AbstractAutowireCapableBeanFactory. Understanding these stages helps developers diagnose bean‑creation issues, manage circular dependencies, and customize bean post‑processing.

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.

Javaspringdependency-injectionSpring Frameworkbean-lifecycle
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.