Backend Development 18 min read

Comprehensive Overview of Spring Bean Lifecycle Extension Points

This article explains the Spring container's refresh process, details every extensible hook in a bean's lifecycle—from ApplicationContextInitializer to DisposableBean—provides usage scenarios, and includes complete Java code snippets illustrating how to implement each extension point for custom middleware and application development.

Architecture Digest
Architecture Digest
Architecture Digest
Comprehensive Overview of Spring Bean Lifecycle Extension Points

Spring's core concept is a container; when the container refreshes, the external view appears calm while the internal processes are highly dynamic. Spring Boot further simplifies configuration by following convention‑over‑configuration and providing auto‑configuration.

1. Background

The author enjoys Spring's auto‑configuration and uses it to create middleware and common utilities that require minimal effort from users. Understanding bean construction, lifecycle, and extension interfaces is essential for writing clean, extensible code.

2. Extension‑Point Invocation Order Diagram

The following diagram (originally an image) shows the sequential order of all extensible points during a bean's lifecycle.

3. ApplicationContextInitializer

Interface: org.springframework.context.ApplicationContextInitializer . It is invoked before the container refreshes, allowing users to perform actions before any beans are instantiated.

public class TestApplicationContextInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("[ApplicationContextInitializer]");
    }
}

Typical use cases include activating early configurations or performing dynamic byte‑code injection before class loading.

4. BeanDefinitionRegistryPostProcessor

Interface: org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor . Executed after reading bean definitions, it provides a hook to add or modify bean definitions before bean instantiation.

public class TestBeanDefinitionRegistryPostProcessor 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");
    }
}

5. BeanFactoryPostProcessor

Interface: org.springframework.beans.factory.config.BeanFactoryPostProcessor . Called after bean definitions are loaded but before any bean instances are created, allowing modification of bean metadata.

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

6. InstantiationAwareBeanPostProcessor

Extends BeanPostProcessor and adds three methods covering the instantiation and property‑population phases.

postProcessBeforeInstantiation : before the bean is instantiated.

postProcessAfterInstantiation : after the bean is instantiated.

postProcessPropertyValues : during property injection (e.g., handling @Autowired ).

postProcessBeforeInitialization and postProcessAfterInitialization remain from BeanPostProcessor .

public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class
beanClass, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before instantiation " + beanName);
        return null;
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after instantiation " + beanName);
        return true;
    }
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] postProcessPropertyValues " + beanName);
        return pvs;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] before initialization " + beanName);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[TestInstantiationAwareBeanPostProcessor] after initialization " + beanName);
        return bean;
    }
}

7. SmartInstantiationAwareBeanPostProcessor

Provides three additional callbacks: predictBeanType , determineCandidateConstructors , and getEarlyBeanReference , useful for type prediction, constructor selection, and early reference exposure during circular dependencies.

public class TestSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    @Override
    public Class
predictBeanType(Class
beanClass, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] predictBeanType " + beanName);
        return beanClass;
    }
    @Override
    public Constructor
[] determineCandidateConstructors(Class
beanClass, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] determineCandidateConstructors " + beanName);
        return null;
    }
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        System.out.println("[TestSmartInstantiationAwareBeanPostProcessor] getEarlyBeanReference " + beanName);
        return bean;
    }
}

8. BeanFactoryAware

Interface: org.springframework.beans.factory.BeanFactoryAware . Called after bean instantiation but before property injection, giving access to the owning BeanFactory for custom logic or caching.

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

9. ApplicationContextAwareProcessor

Although it does not define its own callbacks, it internally triggers six Aware interfaces (EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware) after bean instantiation and before initialization.

10. BeanNameAware

Provides setBeanName(String name) before bean initialization, allowing modification or logging of the bean's registered name.

public class NormalBeanA implements BeanNameAware {
    public NormalBeanA() { System.out.println("NormalBean constructor"); }
    @Override
    public void setBeanName(String name) { System.out.println("[BeanNameAware] " + name); }
}

11. @PostConstruct

Marks a method to be invoked after dependency injection but before InitializingBean.afterPropertiesSet . It is not a Spring‑specific extension point but a standard Java annotation.

public class NormalBeanA {
    public NormalBeanA() { System.out.println("NormalBean constructor"); }
    @PostConstruct
    public void init() { System.out.println("[PostConstruct] NormalBeanA"); }
}

12. InitializingBean

Interface: org.springframework.beans.factory.InitializingBean . The afterPropertiesSet() method runs after all bean properties are set and before the bean is made available.

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

13. FactoryBean

Allows custom creation logic for complex beans. Implementations can control object creation, type, and singleton status.

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

14. SmartInitializingSingleton

Callback afterSingletonsInstantiated() runs after all non‑lazy singleton beans have been fully initialized.

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

15. CommandLineRunner

Single method run(String... args) is executed after the Spring Boot application starts, useful for post‑startup tasks. Multiple runners can be ordered with @Order .

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

16. DisposableBean

Provides destroy() which is called when the bean is being destroyed, typically during application shutdown.

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

17. ApplicationListener

Allows listening to Spring events such as ContextRefreshedEvent , ContextStartedEvent , ContextStoppedEvent , ContextClosedEvent , and RequestHandledEvent . Implementations can react to lifecycle changes or custom events.

18. Conclusion

By understanding and leveraging these Spring and Spring Boot extension points, developers can insert custom logic at virtually any stage of the bean lifecycle, enabling sophisticated middleware, automatic configuration, and fine‑grained control over application behavior.

JavaSpringSpring Bootdependency injectionExtension Pointsbean lifecycle
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

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.