Spring BeanFactoryPostProcessor and BeanPostProcessor
These two classes can be used to get into the spring bean definition registration and initialization.
In case we need to intercept the beans definitions we can use the BeanFactoryPostProcessor
which is executed during the spring bean definitions (before the initialization).
On the other hand in case we need to intercept the beans initialization we can use the BeanPostProcessor
which is executed before and after every bean initialization.
BeanFactoryPostProcessor
We can take the example below for the BeanFacotryPostProcessor
.
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println(getClass().getSimpleName() + "::postProcessorBeanFactory Listing Beans Start" );
Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach(System.out::println);
System.out.println(getClass().getSimpleName() + "::postProcessBeanFactory Listing Beans End\n");
}
}
And you can register it in your configuration class like below:
@ComponentScan(basePackageClasses = ApplicationConfigWithBeanFactoryPostProcessor.class)
public class ApplicationConfigWithBeanFactoryPostProcessor {
/**
* bean declaration is done using a static method.
The reason for this is so that the bean declaration is picked
* up when the context is created, earlier than the configuration class annotated
* with @Configuration, and so the property values are added to the Spring
* environment and become available for injection in the said configuration class,
* before this class is initialized.
*/
@Bean
public static BeanFactoryPostProcessor getPostProcess(){
return new CustomBeanFactoryPostProcessor();
}
}
When we create the spring-context using the test code below
@Test
public void beanFactoryPostProcessorLogs() {
//Execution this code you will see in the logs the definitions of each bean
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfigWithBeanFactoryPostProcessor.class);
}
We will get the following logs
CustomBeanFactoryPostProcessor::postProcessorBeanFactory Listing Beans Start
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
applicationConfigWithBeanFactoryPostProcessor
computer
hardDisk
memory
processor
getPostProcess
CustomBeanFactoryPostProcessor::postProcessBeanFactory Listing Beans End
These logs if you look at the code reflect all the beans that we have in the application. In this case other than the spring beans we have:
- computer
- hardDisk
- memory
- processor
- getPostProcess
as beans in our application
BeanPostProcessor
BeanPostProcessor
has the similar concept but it will be executed before each bean initialization. We can take as an example our class that implements it below:
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(String.format("%s::postProcessBeforeInitialization %s %s", getClass().getSimpleName(), bean.getClass().getSimpleName(), beanName));
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(String.format("%s::postProcessAfterInitialization %s %s", getClass().getSimpleName(), bean.getClass().getSimpleName(), beanName));
return bean;
}
}
Similary registered by the configuration class below:
@ComponentScan(basePackageClasses = ApplicationConfigWithBeanPostProcessor.class)
public class ApplicationConfigWithBeanPostProcessor {
@Bean
public static BeanPostProcessor getPostProcessor(){
return new CustomBeanPostProcessor();
}
}
After executing the context with the application config class above, you will have the following logs:
postProcessorBeforeInitialization ApplicationConfigWithBeanPostProcessor
postProcessAfterInitialization ApplicationConfigWithBeanPostProcessor
postProcessorBeforeInitialization Processor
postProcessAfterInitialization Processor
postProcessorBeforeInitialization Memory
postProcessAfterInitialization Memory
postProcessorBeforeInitialization HardDisk
postProcessAfterInitialization HardDisk
postProcessorBeforeInitialization Computer
postProcessAfterInitialization Computer
With the logs above you can see that before the initialization and after the initialization of the bean the method is executed.