Backend Development 9 min read

Mastering Spring Bean Initialization: @PostConstruct, InitializingBean, and init‑method Explained

This article explains the three Spring bean initialization callbacks—@PostConstruct, InitializingBean, and init‑method—their fixed execution order, underlying processing mechanisms, code examples, and guidance on choosing the most suitable approach for different development scenarios.

Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Xuanwu Backend Tech Stack
Mastering Spring Bean Initialization: @PostConstruct, InitializingBean, and init‑method Explained

Interview Answer: Bean Initialization Callback Mechanism in Spring

The three initialization callbacks provided by Spring—

@PostConstruct

annotation,

InitializingBean

interface, and the custom

init‑method

configuration—are executed in a fixed order after dependency injection and before the bean is ready for use.

First, methods annotated with

@PostConstruct

are invoked, then the

afterPropertiesSet()

method of

InitializingBean

, and finally the user‑defined

init‑method

.

1. @PostConstruct Annotation

Originates from the JSR‑250 specification and is a standard Java EE annotation.

Processed by Spring's

CommonAnnotationBeanPostProcessor

.

Invoked via reflection on the annotated method.

package com.qy.demo;

import javax.annotation.PostConstruct;

public class PostConstructBean {
    public PostConstructBean() {
        System.out.println("Constructor executed - Bean instantiated");
    }

    @PostConstruct
    public void initialize() {
        System.out.println("@PostConstruct method executed - resource initialization");
    }
}

2. InitializingBean Interface

Spring‑provided interface.

Requires implementation of the

afterPropertiesSet()

method.

Called directly without reflection, offering slightly better performance.

package com.qy.demo;

import org.springframework.beans.factory.InitializingBean;

public class InitializingBeanDemo implements InitializingBean {
    public InitializingBeanDemo() {
        System.out.println("Constructor executed - Bean instantiated");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean.afterPropertiesSet() executed - resource initialization");
    }
}

3. init‑method Configuration

Pure configuration, specified in XML or

@Bean

annotation.

Invoked via reflection.

Fully decoupled; no need to implement Spring‑specific interfaces or annotations.

package com.qy.demo;

public class InitMethodBean {
    public InitMethodBean() {
        System.out.println("Constructor executed - Bean instantiated");
    }

    public void init() {
        System.out.println("Custom init‑method executed - resource initialization");
    }
}

Configuration examples:

// Java configuration
@Bean(initMethod = "init")
public InitMethodBean initMethodBean() {
    return new InitMethodBean();
}
<!-- XML configuration -->
<bean id="initMethodBean" class="com.qy.demo.InitMethodBean" init-method="init" />

Execution Order and Internal Principle

The execution order is fixed:

@PostConstruct

annotated method.

InitializingBean.afterPropertiesSet()

method.

Custom

init‑method

method.

Method Call Stack

Spring’s

AbstractAutowireCapableBeanFactory.initializeBean()

orchestrates the three callbacks.

AbstractApplicationContext.refresh()
  -> finishBeanFactoryInitialization(beanFactory)
    -> DefaultListableBeanFactory.preInstantiateSingletons()
      -> getBean() -> createBean()
        -> doCreateBean()
          -> initializeBean(beanName, exposedObject, mbd)
            -> applyBeanPostProcessorsBeforeInitialization() // @PostConstruct
            -> invokeInitMethods() // InitializingBean & init‑method
            -> applyBeanPostProcessorsAfterInitialization()

@PostConstruct Processing

CommonAnnotationBeanPostProcessor

(subclass of

InitDestroyAnnotationBeanPostProcessor

) scans for

@PostConstruct

methods after bean instantiation and invokes them via reflection.

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        metadata.invokeInitMethods(bean, beanName);
    } catch (Throwable ex) {
        // handle exception
    }
    return bean;
}

InitializingBean Processing

If the bean implements

InitializingBean

, Spring directly calls

afterPropertiesSet()

without reflection.

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable {
    if (bean instanceof InitializingBean) {
        ((InitializingBean) bean).afterPropertiesSet();
    }
    // then init‑method handling
}

init‑method Handling

Spring retrieves the method name from the bean definition and invokes it via reflection.

protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd) throws Throwable {
    Method initMethod = ClassUtils.getMethod(bean.getClass(), mbd.getInitMethodName());
    ReflectionUtils.makeAccessible(initMethod);
    initMethod.invoke(bean);
}

Choosing the Right Initialization Approach

@PostConstruct

Pros: Standard Java annotation, reusable outside Spring.

Cons: Requires source code and annotation support.

Best for: Annotation‑driven development, e.g., JPA entities.

InitializingBean

Pros: Tight Spring integration, direct method call.

Cons: Couples code to Spring.

Best for: Internal Spring components needing lifecycle integration.

init‑method

Pros: Fully decoupled, works with third‑party classes.

Cons: String‑based configuration prone to typos.

Best for: Config‑driven setups, third‑party library initialization.

Typical Application Scenarios

Resource Initialization : Starting connection pools, pre‑warming caches.

Parameter Validation : Ensuring required dependencies are injected.

Background Task Startup : Launching scheduled jobs or listeners.

@PostConstruct
public void initializeCache() {
    System.out.println("Initializing cache");
    // preload cache data
}
@Override
public void afterPropertiesSet() {
    if (dataSource == null) {
        throw new IllegalStateException("dataSource must be set");
    }
}
public void init() {
    System.out.println("Starting background scheduled tasks");
    scheduler.startTasks();
}
SpringJava BackendBean InitializationPostConstructInitializingBeaninit-method
Xuanwu Backend Tech Stack
Written by

Xuanwu Backend Tech Stack

Primarily covers fundamental Java concepts, mainstream frameworks, deep dives into underlying principles, and JVM internals.

0 followers
Reader feedback

How this landed with the community

login 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.