Interacting with newly created bean instances using Spring's BeanPostProcessor
Join the DZone community and get the full member experience.
Join For FreeThis article is taken from the book Getting started with Spring Framework
BeanPostProcessor is used to interact with newly created bean instances before and/or after their initialization method is invoked by the Spring container. You can use BeanPostProcessor to execute custom logic before and/or after bean’s initialization method is invoked by the Spring container.
BeanPostProcessor interface defines the following methods:
- Object postProcessBeforeInitialization(Object bean, String beanName) – this method is invoked before the initialization method of a bean instance is invoked
- Object postProcessAfterInitialization(Object bean, String beanName) – this method is invoked after the initialization method of a bean instance is invoked
BeanPostProcessor’s methods accept newly created bean instance and its name as arguments, and return the same or modified bean instance. You configure a BeanPostProcessor implementation in the application context XML file like any other Spring bean. Once the BeanPostProcessor beans are created, the Spring container invokes each BeanPostProcessor’s postProcessBeforeInitialization and postProcessAfterInitialization methods for each bean instance created by the Spring container.
BeanPostProcessor example – Validating bean instances
In a Spring application, you may want to verify that a bean instance is configured correctly before it is injected into dependent beans or accessed by other objects in the application. Let’s see how we can use a BeanPostProcessor implementation to give an opportunity to each bean instance to validate its configuration before the bean instance is made available to dependent beans or other application objects.
The following example listing shows an InstanceValidator interface that must be implemented by beans whose configuration we want to validate using a BeanPostProcessor implementation:
Example listing – InstanceValidator interface
package sample.spring.chapter04.springbankapp.common; public interface InstanceValidator { void validateInstance(); }
InstanceValidator interface defines a validateInstance method that verifies whether the bean instance was correctly initialized or not. We’ll soon see that the validateInstance method is invoked by a BeanPostProcessor implementation.
The following example listing shows the FixedDepositDaoImpl class that implements InstanceValidator interface:
Example listing – FixedDepositDaoImpl class
package sample.spring.chapter04.springbankapp.dao; import org.apache.log4j.Logger; import sample.spring.chapter04.springbankapp.common.InstanceValidator; public class FixedDepositDaoImpl implements FixedDepositDao, InstanceValidator { private static Logger logger = Logger.getLogger(FixedDepositDaoImpl.class); private DatabaseConnection connection; public FixedDepositDaoImpl() { logger.info("FixedDepositDaoImpl's constructor invoked"); } public void initializeDbConnection() { logger.info("FixedDepositDaoImpl's initializeDbConnection method invoked"); connection = DatabaseConnection.getInstance(); } @Override public void validateInstance() { logger.info("Validating FixedDepositDaoImpl instance"); if(connection == null) { logger.error("Failed to obtain DatabaseConnection instance"); } } }
In the above example listing, the initializeDbConnection method is the initialization method that retrieves an instance of DatabaseConnection by calling getInstance static method of DatabaseConnection class. The connection attribute is null if FixedDepositDaoImpl instance fails to retrieve an instance of DatabaseConnection. If connection attribute is null, the validateInstance method logs an error message indicating that the FixedDepositDaoImpl instance is not correctly initialized. As the initializeDbConnection initialization method sets the value of connection attribute, the validateInstance method must be invoked after the initializeDbConnection method. In a real world application development scenario, if a bean instance is not configured correctly, the validateInstance method may take some corrective action or throw a runtime exception to stop the application from starting up. For simplicity, the validateInstance method logs an error message if a bean instance is not configured correctly.
The following example listing shows the InstanceValidationBeanPostProcessor class that implements Spring’s BeanPostProcessor interface, and is responsible for invoking validateInstance method of newly created beans:
Example listing – InstanceValidationBeanPostProcessor class
package sample.spring.chapter04.springbankapp.postprocessor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.core.Ordered; public class InstanceValidationBeanPostProcessor implements BeanPostProcessor, Ordered { private static Logger logger = Logger.getLogger(InstanceValidationBeanPostProcessor.class); private int order; public InstanceValidationBeanPostProcessor() { logger.info("Created InstanceValidationBeanPostProcessor instance"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { logger.info("postProcessBeforeInitialization method invoked"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { logger.info("postProcessAfterInitialization method invoked"); if (bean instanceof InstanceValidator) { ((InstanceValidator) bean).validateInstance(); } return bean; } public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return order; } }
The above example listing shows that the InstanceValidationBeanPostProcessor class implements Spring’s BeanPostProcessor and Ordered interfaces. The postProcessBeforeInitialization method simply returns the bean instance passed to the method. In the postProcessAfterInitialization method, if the bean instance is found to be of type InstanceValidator, the bean instance’s validateInstance method is invoked. This means that if a bean implements InstanceValidator interface, InstanceValidationBeanPostProcessor calls validateInstance method of the bean instance after the initialization method of the bean instance is invoked by the Spring container.
The Ordered interface defines a getOrder method which returns an integer value. The integer value returned by the getOrder method determines the priority of a BeanPostProcessor implementation with respect to other BeanPostProcessor implementations configured in the application context XML file. A BeanPostProcessor with higher order value is considered at a lower priority, and is executed after the BeanPostProcessor implementations with lower order values are executed.
The following example listing shows bean definitions for InstanceValidationBeanPostProcessor class:
Example listing – InstanceValidationBeanPostProcessor bean definition
<bean class="…...springbankapp.postprocessor.InstanceValidationBeanPostProcessor"> <property name="order" value="1" /> </bean>
In the above bean definition, <bean> element’s id attribute is not specified because we typically don’t want InstanceValidationBeanPostProcessor to be a dependency of any other bean. The <property> element sets the value of order property to 1.
You can download the example code for this article from here. To run the example, execute the main method of SpringBankApp class.
Opinions expressed by DZone contributors are their own.
Comments