BeanFactoryPostProcessor interface in Spring resides in org.springframework.beans.factory.config package. BeanFactoryPostProcessor implementation is used to read the configuration metadata and potentially change it before beans are instantiated by IOC container.
You can configure multiple BeanFactoryPostProcessors, you can also control the order in which these BeanFactoryPostProcessors execute by setting the order property. You can set the order property only if the BeanFactoryPostProcessor implements the Ordered interface.
BeanFactoryPostProcessor interface in Spring
BeanFactoryPostProcessor interface is a functional interface meaning it has a single abstract method, that method is postProcessBeanFactory() which you need to implement in order to custom modify the bean definitions.
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
}
Usage of BeanFactoryPostProcessor in Spring
The implementations of BeanFactoryPostProcessor interface are used by Spring framework itself. When you read from property files in Spring and configure the <context:property-placeholder> element that registers PropertySourcesPlaceholderConfigurer which implements BeanFactoryPostProcessor interface and set the properties there in the bean.
Spring BeanFactoryPostProcessor example
Here let’s have a simple example of BeanFactoryPostProcessor in Spring.
The scenario is that you have set the properties in a property file for DB config but for a particular run you want to use the separate schema which is set up in such a way that all the otehr properties remain same except the url. Which means you want to override the url property of the DataSource and modify it so that you can connect to the new Schema.
Though a better option would be to create separate profiles and switch among those profiles but you can access bean definition and modify the value of the property using the BeanFactoryPostProcessor.
db.properties file
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/netjs
db.username=root
db.password=admin
pool.initialSize=5
XML configuration for the datasource
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value = "${db.driverClassName}" />
<property name="url" value = "${db.url}" />
<property name="username" value = "${db.username}" />
<property name="password" value = "${db.password}" />
<property name="initialSize" value = "${pool.initialSize}" /
</bean>
BeanFactoryPostProcessor implementation
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.Ordered;
public class TestDBPostProcessor implements BeanFactoryPostProcessor, Ordered {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
System.out.println("In postProcessBeanFactory");
// Getting the dataSource bean
BeanDefinition bd = beanFactory.getBeanDefinition("dataSource");
if(bd.hasPropertyValues()){
MutablePropertyValues pvs = bd.getPropertyValues();
PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
System.out.println("pv -- " + pv.getName());
// changing value for url property
if(pv.getName().equals("url")){
pvs.add(pv.getName(), "jdbc:mysql://localhost:3306/TestSchema");
}
}
}
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
}
As you can see in the method postProcessBeanFactory() you can get the dataSource bean and modify the bean definition.
To register the BeanFactoryPostProcessor add the following line in your configuration.
<bean class="org.netjs.config.TestDBPostProcessor" />
Here is the method where I want to use the new schema.
To run this example following code can be used.
public List<Employee> findAllEmployees() {
System.out.println("URL " + ((BasicDataSource)jdbcTemplate.getDataSource()).getUrl());
return this.jdbcTemplate.query(SELECT_ALL_QUERY, (ResultSet rs) -> {
List<Employee> list = new ArrayList<Employee>();
while(rs.next()){
Employee emp = new Employee();
emp.setEmpId(rs.getInt("id"));
emp.setEmpName(rs.getString("name"));
emp.setAge(rs.getInt("age"));
list.add(emp);
}
return list;
});
}
public class App {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
("appcontext.xml");
EmployeeDAO dao = (EmployeeDAO)context.getBean("employeeDAOImpl");
List<Employee> empList = dao.findAllEmployees();
for(Employee emp : empList){
System.out.println("Name - "+ emp.getEmpName() + " Age - "
+ emp.getAge());
}
context.close();
}
}
Output
Relevant lines from the console.
In postProcessBeanFactory
pv -- driverClassName
pv -- url
pv -- username
pv -- password
pv – initialSize
URL jdbc:mysql://localhost:3306/TestSchema
That's all for this topic BeanFactoryPostProcessor in Spring Framework. If you have any doubt or any suggestions to make please drop a comment. Thanks!
Related Topics
You may also like -