15 Must-Know SpringBoot Startup Extension Points – Which Have You Used?
This article enumerates fifteen common SpringBoot startup extension points, explains their positions in the bean lifecycle, illustrates each with concrete code snippets and usage scenarios, and provides a visual call‑order diagram to help developers harness these hooks for custom initialization and middleware development.
Extension Point Call Order Diagram
The following diagram shows the order in which all extensible points are invoked during a bean's lifecycle within the Spring container.
1. ApplicationContextInitializer
This callback runs before the ConfigurableApplicationContext is refreshed. Implementations can perform actions such as activating configurations early or injecting bytecode before classes are loaded.
public class TestApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("[ApplicationContextInitializer]");
}
}Three ways to register:
Programmatically via
springApplication.addInitializers(new TestApplicationContextInitializer())Configuration property
context.initializer.classes=com.example.demo.TestApplicationContextInitializerSpring SPI entry in spring.factories:
org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer2. BeanDefinitionRegistryPostProcessor
Invoked after bean definitions are read, allowing dynamic registration of additional BeanDefinition objects, even from outside the classpath.
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");
}
}3. BeanFactoryPostProcessor
Runs after bean definitions are loaded but before bean instantiation, enabling modification of bean metadata.
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("[BeanFactoryPostProcessor]");
}
}4. InstantiationAwareBeanPostProcessor
Extends BeanPostProcessor by adding three methods that operate during the instantiation and property‑injection phases. The five key methods are: postProcessBeforeInstantiation – before new is called postProcessAfterInstantiation – after the object is created postProcessPropertyValues – during property injection (used by @Autowired, @Resource) postProcessBeforeInitialization – before Spring calls initialization callbacks postProcessAfterInitialization – after initialization callbacks
Typical use cases include collecting beans of a certain type or applying uniform property settings.
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;
}
}5. SmartInstantiationAwareBeanPostProcessor
Provides three additional callbacks: predictBeanType – before postProcessBeforeInstantiation, predicts the bean's type for early type lookup. determineCandidateConstructors – after postProcessBeforeInstantiation, selects which constructors to use. getEarlyBeanReference – after postProcessAfterInstantiation, exposes a bean reference to resolve 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;
}
}6. BeanFactoryAware
Single method setBeanFactory is called after bean instantiation but before property injection, allowing access to the owning BeanFactory for custom handling 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());
}
}7. ApplicationContextAwareProcessor
Although not an extension point itself, this processor internally triggers six aware‑interface extensions after bean instantiation and before initialization, covering EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, and ApplicationContextAware. The following diagram highlights these hooks:
8. BeanNameAware
Provides setBeanName before the bean's initialization phase, enabling modification of the bean name prior to registration.
public class NormalBeanA implements BeanNameAware {
public NormalBeanA() { System.out.println("NormalBean constructor"); }
@Override
public void setBeanName(String name) { System.out.println("[BeanNameAware] " + name); }
}9. @PostConstruct
Marks a method to be invoked after postProcessBeforeInitialization and before InitializingBean.afterPropertiesSet. Useful for initializing specific properties.
public class NormalBeanA {
public NormalBeanA() { System.out.println("NormalBean constructor"); }
@PostConstruct
public void init() { System.out.println("[PostConstruct] NormalBeanA"); }
}10. InitializingBean
Single method afterPropertiesSet runs after property injection and before the bean is fully initialized.
public class NormalBeanA implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception { System.out.println("[InitializingBean] NormalBeanA"); }
}11. FactoryBean
Allows custom bean instantiation logic, often used to hide complex creation details. Spring itself provides over 70 implementations. Since Spring 3.0, it supports generics ( FactoryBean<T>).
public class TestFactoryBean implements FactoryBean<TestFactoryBean.TestFactoryInnerBean> {
@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 {}
}12. SmartInitializingSingleton
Method afterSingletonsInstantiated is called after all non‑lazy singleton beans have been fully initialized, allowing post‑processing of the entire singleton set.
public class TestSmartInitializingSingleton implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() { System.out.println("[TestSmartInitializingSingleton]"); }
}13. CommandLineRunner
Single method run(String... args) executes after the application has started. Multiple runners can be ordered with @Order.
public class TestCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception { System.out.println("[TestCommandLineRunner]"); }
}14. DisposableBean
Method destroy() runs when the bean is being destroyed, e.g., during applicationContext.registerShutdownHook().
public class NormalBeanA implements DisposableBean {
@Override
public void destroy() throws Exception { System.out.println("[DisposableBean] NormalBeanA"); }
}15. ApplicationListener
Can listen to Spring's built‑in events such as ContextRefreshedEvent, ContextStartedEvent, ContextStoppedEvent, ContextClosedEvent, and RequestHandledEvent. Implementations allow custom handling of these lifecycle events.
Conclusion
By examining these Spring and SpringBoot extension points, developers gain insight into the bean lifecycle and can strategically inject custom logic at various startup phases, enabling sophisticated initialization and middleware capabilities.
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.
Programmer XiaoFu
xiaofucode.com – a programmer learning guide driven by the pursuit of profit
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.
