Backend Development 19 min read

Comprehensive Overview of Spring & Spring Boot Extension Points and Bean Lifecycle

This article provides a detailed summary of Spring and Spring Boot's bean lifecycle, enumerating all major extension interfaces—including ApplicationContextInitializer, BeanDefinitionRegistryPostProcessor, BeanFactoryPostProcessor, InstantiationAwareBeanPostProcessor, SmartInstantiationAwareBeanPostProcessor, various Aware interfaces, FactoryBean, CommandLineRunner, and ApplicationListener—along with usage scenarios and code examples, enabling developers to customize bean initialization and container behavior.

IT Xianyu
IT Xianyu
IT Xianyu
Comprehensive Overview of Spring & Spring Boot Extension Points and Bean Lifecycle

1. Background

Spring's core concept is a container; when the container refreshes, the internal processes are complex. Spring Boot further encapsulates Spring, following convention‑over‑configuration and providing auto‑configuration, so that adding a dependency often results in a functional feature with almost zero configuration. Understanding the bean construction lifecycle and the various extension interfaces is essential for writing middleware and reusable libraries.

2. Extension Point Call Sequence Diagram

The following diagram (illustrated in the original article) shows the order in which all extensible points are invoked during a bean's lifecycle within the Spring container.

3. ApplicationContextInitializer

org.springframework.context.ApplicationContextInitializer

This callback is invoked before the Spring container is refreshed. Implementations can run custom logic before any beans are instantiated, such as activating configurations or performing byte‑code manipulation.

Typical registration methods:

Programmatically via springApplication.addInitializers(new MyInitializer())

In application.properties with context.initializer.classes=com.example.MyInitializer

Via Spring SPI by adding org.springframework.context.ApplicationContextInitializer=com.example.MyInitializer to spring.factories

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

4. BeanDefinitionRegistryPostProcessor

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

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

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

5. BeanFactoryPostProcessor

org.springframework.beans.factory.config.BeanFactoryPostProcessor

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

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

6. InstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor

Extends BeanPostProcessor with three additional methods covering the instantiation phase and property injection phase, useful for tasks such as custom bean creation, property value manipulation, or collecting beans of a certain type.

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class
beanClass, String beanName) throws BeansException {
        System.out.println("[MyInstantiationAwareBeanPostProcessor] before instantiation " + beanName);
        return null;
    }
    @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;
    }
}

7. SmartInstantiationAwareBeanPostProcessor

org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor

Provides three extra hooks: predictBeanType , determineCandidateConstructors , and getEarlyBeanReference , allowing fine‑grained control over bean type prediction, constructor selection, and early reference exposure for circular dependencies.

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

8. BeanFactoryAware

org.springframework.beans.factory.BeanFactoryAware

Allows a bean to obtain a reference to 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("[MyBeanFactoryAware] " + beanFactory.getBean(MyBeanFactoryAware.class).getClass().getSimpleName());
    }
}

9. ApplicationContextAwareProcessor

org.springframework.context.support.ApplicationContextAwareProcessor

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

EnvironmentAware – access environment properties.

EmbeddedValueResolverAware – resolve ${…} placeholders.

ResourceLoaderAware – load resources from the classpath.

ApplicationEventPublisherAware – publish application events.

MessageSourceAware – obtain internationalization messages.

ApplicationContextAware – obtain the full ApplicationContext for bean lookup.

10. BeanNameAware

org.springframework.beans.factory.BeanNameAware

Provides the bean name before initialization, enabling custom naming logic.

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

11. @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");
    }
}

12. InitializingBean

org.springframework.beans.factory.InitializingBean

Provides a single afterPropertiesSet method invoked after property injection and before the bean is made available.

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

13. FactoryBean

org.springframework.beans.factory.FactoryBean

Allows custom creation logic for complex beans; Spring itself provides dozens of implementations.

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

14. 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]");
    }
}

15. CommandLineRunner

org.springframework.boot.CommandLineRunner

Runs after the Spring Boot application has 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]");
    }
}

16. DisposableBean

org.springframework.beans.factory.DisposableBean

Provides a destroy method called when the bean is being destroyed, e.g., during context shutdown.

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

17. ApplicationListener

org.springframework.context.ApplicationListener

Listens to Spring events such as ContextRefreshedEvent , ContextStartedEvent , ContextStoppedEvent , ContextClosedEvent , and RequestHandledEvent , allowing custom behavior at various lifecycle stages.

18. Conclusion

The article summarizes the major Spring & Spring Boot extension points, illustrating how developers can hook into different phases of bean creation and container startup to implement custom initialization, resource loading, and cleanup logic. The next article will discuss controlling bean loading order in Spring Boot.

JavaSpringSpringBootdependency injectionExtension Pointsbean lifecycleapplication-context
IT Xianyu
Written by

IT Xianyu

We share common IT technologies (Java, Web, SQL, etc.) and practical applications of emerging software development techniques. New articles are posted daily. Follow IT Xianyu to stay ahead in tech. The IT Xianyu series is being regularly updated.

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.