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.
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
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 ApplicationContextAwareBeanNameAware
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
