Unlocking Spring Bean Lifecycle: 17 Extension Points Every Developer Should Master

This article systematically catalogs every Spring and Spring Boot extension interface—from ApplicationContextInitializer to DisposableBean—illustrates their invocation order with a diagram, explains practical use‑cases, and provides concrete code samples for each hook, enabling developers to tap into the bean lifecycle for custom initialization, monitoring, and cleanup.

Architect
Architect
Architect
Unlocking Spring Bean Lifecycle: 17 Extension Points Every Developer Should Master

Spring’s core concept is a container that asseives beans. During a container refresh a large number of extension points are invoked, allowing custom logic at virtually any stage of bean construction. Spring Boot adds auto‑configuration and convention‑over‑configuration, reducing the amount of manual setup.

Extension‑point invocation order diagram

Bean lifecycle diagram
Bean lifecycle diagram

ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

Runs before the Spring ConfigurableApplicationContext is refreshed. Typical uses are early configuration activation or byte‑code manipulation before classes are loaded.

Register programmatically: springApplication.addInitializers(new MyInitializer()) Configure via property: context.initializer.classes=com.example.MyInitializer SPI entry in spring.factories:

org.springframework.context.ApplicationContextInitializer=com.example.MyInitializer
public class MyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext ctx) {
        System.out.println("[ApplicationContextInitializer]");
    }
}

BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

Invoked after bean definitions are read, allowing dynamic registration of additional bean definitions (even from outside the classpath).

Register via @Component or SPI entry in spring.factories.

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanDefinitionRegistry");
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanDefinitionRegistryPostProcessor] postProcessBeanFactory");
    }
}

BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

Runs after bean definitions are loaded but before any bean is instantiated, enabling modification of bean definition metadata.

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanFactoryPostProcessor]");
    }
}

InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

Extends BeanPostProcessor with callbacks before and after bean instantiation, during property population, and before/after initialization. postProcessBeforeInstantiation: before new the bean. postProcessAfterInstantiation: after the bean is created. postProcessPropertyValues: during @Autowired / @Resource injection. postProcessBeforeInitialization: before Spring context injection. postProcessAfterInitialization: after Spring context injection.

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] before instantiation " + beanName);
        return null; // return bean instance to short‑circuit default instantiation
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] after instantiation " + beanName);
        return true;
    }
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);
        return pvs;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] before initialization " + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] after initialization " + beanName);
        return bean;
    }
}

SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

Provides three additional callbacks useful for type prediction, constructor selection, and early bean exposure in circular‑dependency scenarios. predictBeanType: called before postProcessBeforeInstantiation to guess the bean’s type. determineCandidateConstructors: called after postProcessBeforeInstantiation to choose which constructors are eligible. getEarlyBeanReference: called after postProcessAfterInstantiation to expose a bean reference early (e.g., for circular dependencies).

public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[MySmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);
        return beanClass;
    }
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[MySmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);
        return null; // let Spring use default constructors
    }
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        System.out.println("[MySmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);
        return bean;
    }
}

BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

Allows a bean to obtain the owning BeanFactory after instantiation but before property injection.

public class MyBeanFactoryAware implements BeanFactoryAware {
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanFactoryAware] beanFactory=" + beanFactory);
    }
}

ApplicationContextAwareProcessor (internal aware interfaces)

org.springframework.context.support.ApplicationContextAwareProcessor

Internally triggers six Aware interfaces after bean instantiation and before property population:

EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware

BeanNameAware

org.springframework.beans.factory.BeanNameAware

Provides the bean name before initialization via setBeanName, allowing custom naming logic.

public class MyBeanNameAware implements BeanNameAware {
    @Override
    public void setBeanName(String name) {
        System.out.println("[BeanNameAware] bean name=" + name);
    }
}

@PostConstruct

javax.annotation.PostConstruct

Marks a method to be invoked after dependency injection but before any InitializingBean callbacks.

public class MyBean {
    @PostConstruct
    public void init() {
        System.out.println("[PostConstruct] MyBean initialized");
    }
}

InitializingBean

org.springframework.beans.factory.InitializingBean

Defines a single afterPropertiesSet method executed after all bean properties have been set and before the bean is put into use.

public class MyInitializingBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("[InitializingBean] afterPropertiesSet called");
    }
}

FactoryBean

org.springframework.beans.factory.FactoryBean

Enables custom bean creation logic. The interface can be generic ( FactoryBean<T>) since Spring 3.0.

public class MyFactoryBean implements FactoryBean<MyFactoryBean.MyInnerBean> {
    @Override
    public MyInnerBean getObject() throws Exception {
        System.out.println("[FactoryBean] getObject");
        return new MyInnerBean();
    }
    @Override
    public Class<?> getObjectType() {
        return MyInnerBean.class;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
    public static class MyInnerBean {}
}

SmartInitializingSingleton

org.springframework.beans.factory.SmartInitializingSingleton

Callback invoked after all non‑lazy singleton beans have been instantiated.

public class MySmartInitializingSingleton implements SmartInitializingSingleton {
    @Override
    public void afterSingletonsInstantiated() {
        System.out.println("[SmartInitializingSingleton] all singletons ready");
    }
}

CommandLineRunner

org.springframework.boot.CommandLineRunner

Runs a single run(String... args) method after the application context is fully started. Multiple runners can be ordered with @Order.

public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("[CommandLineRunner] application started");
    }
}

ApplicationListener

org.springframework.context.ApplicationListener

Allows listening to Spring events. Common built‑in events include: ContextRefreshedEvent – published when the ApplicationContext is initialized or refreshed. ContextStartedEvent – published when ConfigurableApplicationContext.start() is called. ContextStoppedEvent – published when ConfigurableApplicationContext.stop() is called. ContextClosedEvent – published when the context is closed. RequestHandledEvent – web‑specific event indicating an HTTP request has been processed.

public class MyListener implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("[ApplicationListener] Context refreshed");
    }
}

DisposableBean

org.springframework.beans.factory.DisposableBean

Provides a destroy() method called during bean destruction, typically when the application context shuts down.

public class MyDisposableBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        System.out.println("[DisposableBean] bean destroyed");
    }
}

Understanding and leveraging these extension points enables developers to insert custom logic at any stage of the Spring bean lifecycle, facilitating advanced initialization, monitoring, and cleanup strategies.

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.

BackendJavaspringSpring Bootdependency-injectionExtension PointsSpring Frameworkbean-lifecycle
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.