SpringBoot Extension Interfaces: BeanPostProcessor, BeanFactoryPostProcessor
This article introduces the key SpringBoot extension interfaces—including BeanPostProcessor, BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor, SmartInstantiationAwareBeanPostProcessor, SmartInitializingSingleton, ApplicationContextInitializer, EnvironmentPostProcessor, and the *Runner interfaces—explaining their purposes, usage patterns, and providing concrete code examples to help developers customize and extend SpringBoot applications effectively.
Environment: SpringBoot 2.7.16
1. Introduction
In SpringBoot project development, extension interfaces play a crucial role. They are essential for implementing functional extensions, improving flexibility, and facilitating maintenance. Mastering these interfaces helps developers increase development efficiency and project quality.
2. Extension Interfaces
2.1 BeanPostProcessor
This interface processes beans before and after initialization. Implementing it allows enhancement of all or specific beans, such as modifying bean instances or creating proxies.
<code>@Component
public class PackBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前处理逻辑...");
// TODO
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后处理逻辑...");
// TODO
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
</code>Both the before and after methods can manipulate the bean being created.
2.2 BeanFactoryPostProcessor
This interface allows custom modification of BeanDefinition objects before any beans are instantiated.
<code>@Component
public class PackBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition bd = beanFactory.getBeanDefinition("userService");
bd.getPropertyValues().addPropertyValue("name", "Pack");
}
}
</code>It runs after the container starts but before bean instantiation, enabling changes such as setting a property value on UserService.
2.3 BeanDefinitionRegistryPostProcessor
Extends BeanFactoryPostProcessor and can also register new bean definitions dynamically.
<code>@Component
public class PackBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// modify existing beans
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(UserService.class).getBeanDefinition();
registry.registerBeanDefinition("userService", beanDefinition);
}
}
</code>The postProcessBeanDefinitionRegistry method can register beans based on conditions.
2.4 SmartInstantiationAwareBeanPostProcessor
This interface extends InstantiationAwareBeanPostProcessor and provides early bean reference exposure, pre‑instantiation, post‑instantiation, property population, and early reference methods.
<code>@Component
public class PackSmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
// create proxy before actual bean instance
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
// return false to skip property population
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
// modify property values
return null;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
// expose early reference
return bean;
}
}
</code>2.5 SmartInitializingSingleton
Executed after all singleton beans have been instantiated, allowing custom logic that depends on the fully initialized container.
<code>@Component
public class PackSmartInitializingSingleton implements SmartInitializingSingleton {
@Resource
private ApplicationContext context;
@Override
public void afterSingletonsInstantiated() {
// custom logic, e.g., obtain a bean and invoke init()
UserService us = context.getBean(UserService.class);
us.init();
}
}
</code>2.6 ApplicationContextInitializer
Runs before the Spring container refresh, enabling custom configuration of the ApplicationContext.
<code>public class PackApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableWebApplicationContext> {
@Override
public void initialize(ConfigurableWebApplicationContext applicationContext) {
// custom configuration logic
}
}
</code>It must be registered via the Spring factories file, not with @Component:
<code>org.springframework.context.ApplicationContextInitializer=\
com.pack.expansions.PackApplicationContextInitializer
</code>2.7 EnvironmentPostProcessor
Allows early manipulation of the SpringBoot environment, such as loading additional property sources.
<code>public class PackEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
try {
List<PropertySource<?>> list = sourceLoader.load("pack", new ClassPathResource("com/pack/binder/properties/pack.yml"));
list.forEach(propertySource -> environment.getPropertySources().addLast(propertySource));
} catch (IOException e) {
e.printStackTrace();
}
}
}
</code>Registration is also done via the factories file:
<code>org.springframework.boot.env.EnvironmentPostProcessor=\
com.pack.binder.properties.PackEnvironmentPostProcessor
</code>2.8 *Runner Interfaces
SpringBoot provides ApplicationRunner and CommandLineRunner, which are invoked after the application has started.
<code>@Component
public class PackApplicationRunner implements ApplicationRunner, CommandLineRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// ApplicationRunner callback
}
@Override
public void run(String... args) throws Exception {
// CommandLineRunner callback
}
}
</code>These interfaces enable execution of custom logic at the very end of the startup process.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.