Home » BeanFactoryPostProcessor example

BeanFactoryPostProcessor example

BeanFactoryPostProcessor with example

1. Overview

In this article, we will discuss the BeanFactoryPostProcessor with an example.

2. BeanFactoryPostProcessor

A bean factory post-processor is a java class that implements the org.springframework.beans.factory.config.BeanFactoryPostProcessor interface. Based on the Spring container type, you must execute manually:

  1. BeanFactory - Manual
  2. ApplicationContext - Automatic.

To know the differences between BeanFactory and ApplicationContext, see this article.

The Bean factory post-processors enable you to apply changes to the BeanFactory or ApplicationContext after its construction.

Spring includes several pre-existing bean factory post-processors, such as:

  1. PropertyResourceConfigurer 
  2. PropertyPlaceHolderConfigurer
  3. BeanNameAutoProxyCreator - useful for wrapping other beans transactionally or with any other kind of proxy.

You can also implement the BeanFactoryPostProcessor interface and create custom bean factory post-processors.

As mentioned earlier, you must manually apply the BeanFactoryPostProcessor in case of BeanFactory. For example, the following code applies the PropertyPlaceholderConfigurer manually.

BeanDefinitionRegistry beanDefinitionRegistry = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanDefinitionRegistry);
reader.loadBeanDefinitions(new ClassPathResource("config.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new ClassPathResource("jdbc.properties"));
cfg.postProcessBeanFactory(beanDefinitionRegistry);

However, an ApplicationContext will detect any beans which are deployed into it which implement the BeanFactoryPostProcessor interface, and automatically use them as bean factory post-processors.

Nothing else needs to be done other than deploying these post-processor in a similar fashion to any other bean.

Since this manual step is not convenient, and ApplictionContexts are functionally supersets of BeanFactories, it is generally recommended that ApplicationContext variants are used when bean factory post-processors are needed.

Let’s discuss the BeanFactoryPostProcessor example.

3. BeanFactoryPostProcessor example

3.1. PropertyPlaceholderConfigurer example

The PropertyPlaceholderConfigurer, implemented as a bean factory post-processor, is used to externalize some property values from a BeanFactory definition, into another separate file in Java Properties format.

This is useful to allow the person deploying an application to customize some key properties (for example database URLs, usernames and passwords), without the complexity or risk of modifying the main XML definition file or files for the BeanFactory.

Assume a Bean definition where a DataSource with placeholder values is defined:

For example, we defined a data source, and configured some properties from an external Properties file.

At runtime, we will apply a PropertyPlaceholderConfigurer to the BeanFactory which will replace some properties of the datasource:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

The actual values come from another file in Properties format:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

To use this with a BeanFactory, you need to execute the bean factory post-processor manually:

BeanDefinitionRegistry beanDefinitionRegistry = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanDefinitionRegistry);
reader.loadBeanDefinitions(new ClassPathResource("config.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new ClassPathResource("jdbc.properties"));
cfg.postProcessBeanFactory(beanDefinitionRegistry);
Note that ApplicationContexts can automatically recognize and apply beans deployed in them which implement BeanFactoryPostProcessor. 

The PropertyPlaceHolderConfigurer looks not only for properties in the Properties file you specify but also checks against the Java System properties if it cannot find a property you are trying to use.

We can customize this behavior by setting the systemPropertiesMode property of the configure.

  1. SYSTEM_PROPERTIES_MODE_OVERRID - always override
  2. SYSTEM_PROPERTIES_MODE_NEVER - never override
  3. SYSTEM_PROPERTIES_MODE_FALLBACK - override only if the property not found in the specified properties file
cfg.setSystemPropertiesMode(PropertyPlaceHolderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER);

3.2. PropertyOverrideConfigurer BeanFactoryPostProcessors

The PropertyOverrideConfigurer, another bean factory post-processor, is like the PropertyPlaceholderConfigurer, but in contrast to the latter, the original bean definitions can have default values or no values at all for bean properties.

If an overriding Properties file does not have an entry for a certain bean property, it uses the default context definition.

Note that the bean factory definition is not aware of being overridden, so it is not immediately obvious when looking at the XML definition file that the override configurer is being used.

In case that there are multiple PropertyOverrideConfigurers that define different values for the same bean property, the last one will win (because of the overriding mechanism).

You must specify the bean name followed by the property name in your Properties file configuration:

beanName.property=value

For example, the dataSource is the bean name and driverClassName and URL are properties:

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb

3. Conclusion

To sum up, we have learned the BeanFactoryPostProcessor with a pre-existing processor example. You can refer to our GitHub repository for code samples.

Leave a Reply

Your email address will not be published.