Sunday, June 17, 2018

BeanFactoryPostProcessor in Spring Framework

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 Spring 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 class

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.

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;
        });

}
To run this example following code can be used.
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!

>>>Return to Spring Tutorial Page


Related Topics

  1. BeanPostProcessor in Spring Framework
  2. ApplicationContextAware And BeanNameAware Interfaces in Spring Framework
  3. BeanFactoryAware Interface in Spring Framework
  4. Injecting Inner Bean in Spring
  5. Circular Dependency in Spring Framework

You may also like-

  1. Insert\Update Using JDBCTemplate in Spring Framework
  2. JDBCTemplate with ResultSetExtractor Example in Spring
  3. Run Time Injection Using Spring Expression Language(SpEL)
  4. Using depends-on Attribute in Spring
  5. How HashMap Internally Works in Java
  6. Covariant Return Type in Java
  7. Spliterator in Java
  8. Replica Placement Policy in Hadoop Framework

No comments:

Post a Comment