1. Overview
In this article, we will discuss the PropertyPlaceHolderConfigurer 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:
BeanFactory
– ManualApplicationContext
– 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:
PropertyResourceConfigurer
PropertyPlaceHolderConfigurer
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.
2.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 thatApplicationContexts
can automatically recognize and apply beans deployed in them which implementBeanFactoryPostProcessor
.
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.
SYSTEM_PROPERTIES_MODE_OVERRID
– always overrideSYSTEM_PROPERTIES_MODE_NEVER
– never overrideSYSTEM_PROPERTIES_MODE_FALLBACK
– override only if the property not found in the specified properties file
cfg.setSystemPropertiesMode(PropertyPlaceHolderConfigurer.SYSTEM_PROPERTIES_MODE_NEVER);
3. Conclusion
To sum up, we have learned the PropertyPlaceHolderConfigurer with an example. You can refer to our GitHub repository for code samples.