BeanPostProcessor interface allows you to execute some code or perform some action on the bean before its initialization callbacks (afterPropertiesSet method of InitializingBean interface or method specified in init-method attribute is called) and after its initialization callbacks have executed.
Spring provides 28 implementations out of the box for BeanPostProcessors
that handle standard functions like autowiring, applying AOP advice. So it is
highly unlikely that you would be creating your own post processor. Instead you
would be using 1 available out of the box. You would be using them indirectly
by using standard spring features such as applying validation annotations on a
method parameter which applies MethodValidationPostProcessor, or making method
calls @Async which applies AsyncAnnotationBeanPostProcessor.
Here is a brief overview of the bean lifecycle.
- Create the bean instance either by a constructor or by a factory method.
- Set the values and bean references to the bean properties.
- Call the setter methods defined in the all the aware interfaces. (setBeanFactory() method for beans implementing BeanFactoryAware interface, setApplicationContext() method for beans implementing ApplicationContextAware interface.)
- Pass the bean instance to the postProcessBeforeInitialization() method of each bean post processor.
- Call the initialization callback methods.
- Pass the bean instance to the postProcessAfterInitialization() method of each bean post processor.
- The bean is ready to be used.
- When the container is shut down, call the destruction callback methods. (destroy() method of the DisposableBean interface method specified in destory-method attribute of bean declaration)
This post tries to give you a feel of BeanPostProcessor.
We will be using Java configuration to create beans.
@Configuration
@ComponentScan(basePackages= {"com.rizwan.test.spring_bean_postprocessor_demo"})
public class AppConfig {
@Bean(initMethod="init", destroyMethod="destroyMethod")
public EmployeeDAO employeeDAO() {
return new EmployeeDAO();
}
}
@ComponentScan(basePackages= {"com.rizwan.test.spring_bean_postprocessor_demo"})
public class AppConfig {
@Bean(initMethod="init", destroyMethod="destroyMethod")
public EmployeeDAO employeeDAO() {
return new EmployeeDAO();
}
}
In the @Bean annotation above, initMethod specifies method name that must be called after creating a new instance of that. It will be called after bean has been instantiated and initialized. destroyMethod gives the name of method that will be called when container is shutdown. It can contain code that will allow us to free resources held by the bean.
Let us create a dummy bean which implements InitializingBean, DestroyableBean. This will allow us to see in exactly what sequence are all these methods called.
public class EmployeeDAO implements InitializingBean, DisposableBean {
public void afterPropertiesSet() {
System.out.println("Inside after properties set of InitializatingBean");
}
public void destroy() {
System.out.println("Destroy method of Disposable bean");
}
// Check if init method can return value
public void init() {
System.out.println("Init method of EmployeeDAO");
}
public void destroyMethod() {
System.out.println("Destroy method of EmployeeDAO");
}
public String getEmployeeName(String empId) {
//for simplicity let me return a fixed string regardless of the empId passed in.
return "Rizwan";
}
}
public void afterPropertiesSet() {
System.out.println("Inside after properties set of InitializatingBean");
}
public void destroy() {
System.out.println("Destroy method of Disposable bean");
}
// Check if init method can return value
public void init() {
System.out.println("Init method of EmployeeDAO");
}
public void destroyMethod() {
System.out.println("Destroy method of EmployeeDAO");
}
public String getEmployeeName(String empId) {
//for simplicity let me return a fixed string regardless of the empId passed in.
return "Rizwan";
}
}
Here is out CustomBeanPostProcessor.
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Post processing bean with name " + beanName + " before initialization.");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Post processing bean " + beanName + " after initialization");
return bean;
}
}
public class CustomBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Post processing bean with name " + beanName + " before initialization.");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Post processing bean " + beanName + " after initialization");
return bean;
}
}
Please note that it must be declared as a @Component for spring to apply it to beans or it you need to a bean of that type in AppConfig class.
public static void main( String[] args )
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
@SuppressWarnings("unused")
EmployeeDAO employeeDAO = context.getBean(EmployeeDAO.class);
context.close();
}
{
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
@SuppressWarnings("unused")
EmployeeDAO employeeDAO = context.getBean(EmployeeDAO.class);
context.close();
}
Output:
Post processing bean with name employeeDAO before initialization.
Inside after properties set of InitializatingBean
Init method of EmployeeDAO
Post processing bean employeeDAO after initialization
Destroy method of Disposable bean
Destroy method of EmployeeDAO
Inside after properties set of InitializatingBean
Init method of EmployeeDAO
Post processing bean employeeDAO after initialization
Destroy method of Disposable bean
Destroy method of EmployeeDAO
Output clearly indicates that InitializingBean and DisposableBean interfaces are applied before init-method and destroy-method respectively.
Please note that the CustomBeanPostProcessor was applied to all the beans including AppConfig and an internalEventListenerProcessor created by Spring. For simplicity I have included output only for the employeeDAO.
Hope my post helps someone. Happy learning :)