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.

Programmer XiaoFu
Programmer XiaoFu
Programmer XiaoFu
15 Must-Know SpringBoot Startup Extension Points – Which Have You Used?

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.TestApplicationContextInitializer

Spring SPI entry in spring.factories:

org.springframework.context.ApplicationContextInitializer=com.example.demo.TestApplicationContextInitializer

2. 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backendJavaSpringBootExtensionPointsBeanLifecycle
Programmer XiaoFu
Written by

Programmer XiaoFu

xiaofucode.com – a programmer learning guide driven by the pursuit of profit

0 followers
Reader feedback

How this landed with the community

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.