Home » Java » Enterprise Java » Spring 3.1 – Loading Properties For XML Configuration From Database

About Allen Chee

Allen Chee
Allen is a software developer working in the banking domain. Apart from hacking code and tinkering with technology, he reads a lot about history, so that mistakes of the past need not be repeated if they are remembered.

Spring 3.1 – Loading Properties For XML Configuration From Database

Spring makes it easy to inject values obtained from properties files via its PropertyPlaceholderConfigurer and (pre-Spring 3.1) PropertySourcesPlaceholderConfigurer (Spring 3.1). These classes implement the BeanFactoryPostProcessor interface, which enables them to manipulate the values within the Spring XML configuration file before the beans are initialized. So if you specify ${jdbc.driverClassName} to be set to the property ‘driverClassName’, this variable will be replaced/swapped with the value with the key ‘jdbc.driverClassName’ in a properties file.

Apart from properties files, the database table can also be a place to get key-value pairs. Great, so just extend the PropertySourcesPlaceholderConfigurer, and have it read a table containing the key-value pairs, populate them and we’re done!

However, there’s a slight problem. If the DataSource bean also relies on values obtained from a properties file (e.g. JDBC URL, username, password), and being good Springers, inject this bean to the bean class extending PropertySourcesPlaceholderConfigurer, the bean container will fail to startup properly, because the ‘jdbc.driverClassName’ variable cannot be resolved. Strange, but true.

The reason for this is that any bean injected into a BeanFactoryPostProcessor class will trigger bean initialization BEFORE the BeanFactoryPostProcessor classes are run. You know, dependency injection…all depending beans have to be ready before being injected into the consumer. So this creates a cyclic-dependency kind of thing. All dependencies in the XML configuration are resolved first before the BeanFactoryPostProcessor classes are run.

So, how to go about this? Well, there’s a trick you can employ. A BeanFactoryPostProcessor class has access to the ConfigurableListableBeanFactory object via the ‘postProcessBeanFactory’ method. From this object, you can do a ‘getBean’ and get a reference of any bean with an id. And guess what, you can get the vaunted DataSource bean without triggering premature bean initialization.

Let’s say there’s a table ‘sys_param’ with the following data:

-------------- --------------
service.charge 1.5
rebate.amount 15.99

The DbPropertySourcesPlaceholderConfigurer is shown here:

package org.gizmo.labs.utils.spring;

import javax.sql.DataSource;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

public class DbPropertySourcesPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
		DataSource dataSource = beanFactory.getBean(DataSource.class);
		DbProperties dbProps = new DbProperties(dataSource);


The DbProperties class will make use of the DataSource reference and queries the database to get the key-value pairs:

package org.gizmo.labs.utils.spring;

import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;

public class DbProperties extends Properties
	private final Logger logger = LoggerFactory.getLogger(DbProperties.class);
	private static final long serialVersionUID = 1L;

	public DbProperties(DataSource dataSource)
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); 
                     > l = jdbcTemplate.queryForList('select param_cd, param_value from sys_param');


                       m: l)
			logger.debug('Loading from DB: [{}:{}]', m.get('PARAM_CD'), m.get('PARAM_VALUE'));
			setProperty((m.get('PARAM_CD')).toString(), (m.get('PARAM_VALUE')).toString());

To demonstrate that the values from the table are properly injected, here’s the class which acts as the consumer:

package org.gizmo.labs.utils.spring;

import java.math.BigDecimal;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

public class DbPropConsumer implements InitializingBean
	private final Logger logger = LoggerFactory.getLogger(DbPropConsumer.class);

	private BigDecimal serviceCharge;
	private double rebateAmount;
	private String smtpIp;

	public void afterPropertiesSet() throws Exception
		logger.debug('I have consumed: {}', this);

	public String toString()
		return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);

	public BigDecimal getServiceCharge() {
		return serviceCharge;

	public void setServiceCharge(BigDecimal serviceCharge) {
		this.serviceCharge = serviceCharge;

	public double getRebateAmount() {
		return rebateAmount;

	public void setRebateAmount(double rebateAmount) {
		this.rebateAmount = rebateAmount;

	public String getSmtpIp() {
		return smtpIp;

	public void setSmtpIp(String smtpIp) {
		this.smtpIp = smtpIp;


Last but not least, the Spring configuration (DataSource bean not shown, simplified for clarity):


The first 2 bean definitions are the BeanFactoryPostProcessor classes, and to ensure the first one is run first, the ‘order’ property is set (lower means higher precedence).

For the DbPropertySourcesPlaceholderConfigurer, a different placeholder prefix and suffix is used for clarity (notice the placeholders for DbPropConsumer).

So, upon Spring container startup, you should be able to view a similar output as below:

2012-09-18 00:03:14, DEBUG, org.gizmo.labs.utils.spring.DbProperties, Loading from DB: [service.charge:1.5]
2012-09-18 00:03:14, DEBUG, org.gizmo.labs.utils.spring.DbProperties, Loading from DB: [rebate.amount:15.99]
2012-09-18 00:03:14, DEBUG, org.gizmo.labs.utils.spring.DbProperties, Loading from DB: [smtp.ip:]
2012-09-18 00:03:14, DEBUG, org.gizmo.labs.utils.spring.DbPropConsumer, I have consumed: org.gizmo.labs.utils.spring.DbPropConsumer@189b939[


Reference: Spring 3.1 – Loading Properties For XML Configuration From Database from our JCG partner Allen Julia at the YK’s Workshop blog.

(0 rating, 0 votes)
You need to be a registered member to rate this.
1 Comment Views Tweet it!
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Leave a Reply

1 Comment threads
0 Thread replies
Most reacted comment
Hottest comment thread
1 Comment authors
Dharmendra Parakh Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

newest oldest most voted
Notify of
Dharmendra Parakh
Dharmendra Parakh

Hello Allen,

I tried suggested approach, but it did not work for me. I am using spring 4.2.4. I see that postProcessBeanFactory is invoked only after resolving other beans. So I always get this exception if any of the bean uses a property:

Exception in thread “main” org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name ‘customer’ defined in class path resource [test-context.xml]: Could not resolve placeholder ‘configParam’ in value “${configParam}”; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘configParam’ in value “${configParam}”
at org.springframework.beans.factory.config.PlaceholderConfigurerSupport.doProcessProperties(PlaceholderConfigurerSupport.java:228)

Please advice.