Comprehensive Overview of Spring and Spring Boot Extension Points and Bean Lifecycle
This article provides a detailed walkthrough of Spring and Spring Boot's bean lifecycle, explaining each extension point—from ApplicationContextInitializer to CommandLineRunner—illustrating their usage with code examples and describing practical scenarios for customizing bean creation, initialization, and destruction.
1. Background
Spring's core concept is a container; when the container refreshes, the outside appears calm while the inside undergoes complex processing. Spring Boot further simplifies configuration by following "convention over configuration" and providing auto‑configuration, allowing most functionality with minimal setup.
2. Extension Point Invocation Order
The following diagram (originally an image) shows the order in which Spring invokes all extensible points during bean lifecycle. Each point is discussed below.
3. ApplicationContextInitializer
Callback before the ConfigurableApplicationContext is refreshed, allowing custom actions before the container is fully initialized.
public class TestApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("[ApplicationContextInitializer]");
}
}Three ways to register:
springApplication.addInitializers(new TestApplicationContextInitializer())
context.initializer.classes=com.example.demo.TestApplicationContextInitializer
spring.factories entry: org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer
4. BeanDefinitionRegistryPostProcessor
Executed after bean definitions are read, allowing dynamic registration of additional bean definitions.
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
Runs after bean definitions are loaded but before any bean is instantiated, enabling 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 with additional callbacks for instantiation and property population phases.
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@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;
}
@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;
}
}7. SmartInstantiationAwareBeanPostProcessor
Provides three additional hooks: predictBeanType, determineCandidateConstructors, and getEarlyBeanReference.
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
Allows a bean to obtain the owning BeanFactory before property injection.
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
Internally triggers six aware interfaces (EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, ApplicationContextAware) after bean instantiation and before property population.
10. BeanNameAware
public class NormalBeanA implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("[BeanNameAware] " + name);
}
}11. @PostConstruct
Method annotated with @PostConstruct runs after dependency injection but before any custom init methods.
public class NormalBeanA {
@PostConstruct
public void init() {
System.out.println("[PostConstruct] NormalBeanA");
}
}12. InitializingBean
public class NormalBeanA implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("[InitializingBean] NormalBeanA");
}
}13. FactoryBean
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
public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("[TestSmartInitializingSingleton]");
}
}15. CommandLineRunner
public class TestCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("[TestCommandLineRunner]");
}
}16. DisposableBean
public class NormalBeanA implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("[DisposableBean] NormalBeanA");
}
}17. ApplicationListener
Can listen to built‑in events such as ContextRefreshedEvent, ContextStartedEvent, ContextStoppedEvent, ContextClosedEvent, and RequestHandledEvent, enabling custom logic at various points of the application lifecycle.
18. Conclusion
By understanding and leveraging these Spring and Spring Boot extension points, developers can customize bean creation, initialization, and destruction to fit middleware or business needs, achieving fine‑grained control over the application startup process.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.