Ben Northrop


Decisions and software development


6 Tips for Managing Property Files with Spring


(43 comments)
April 20th 2009


What could be simpler than property files? In an enterprise application, it turns out, many things! In this post I’ll take a look at a few subtle complexities to managing properties in an enterprise Java Spring application, and hopefully demonstrate how a little fore-thought in design can yield big savings in terms of time, confusion, bugs, and gray hair down the road.

Types of Properties

Before designing an approach to managing property files, it's critical first to understand the types of properties are to be managed. Here are four characteristics to consider:

Each of these special characteristics adds a degree of complexity to applications - necessitating additional infrastructure beyond the simple Java Properties class.

Spring’s PropertyPlaceholderConfigurer

Fortunately for us, the Spring framework, with the PropertyPlaceholderConfigurer and PropertyOverrideConfigurer, provides the features and hooks we need to manage these cases (with the exception “dynamic” properties). And true to its philosophy, Spring makes simple things simple, and complicated things possible.

The PropertyPlaceholderConfigurer allows properties to be pulled in to the application context file. For example, in the simplest case, a property “db.user” defined in database.properties could be pulled into the ${db.user} placeholder:

<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:database.properties</value>
</list>
</property>
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${db.user}"/>
<property name="password" value="${db.password}"/>
...
</bean>

The PropertyOverrideConfigurer works in the opposite way, pushing properties from property files into properties in the context file (without having to specifically define a place holder – e.g. ${db.user}). These are both well documented in the Spring API and documentation.

Tips

Given the different possible types of properties, and Spring's property framework, here are a few tips for managing them:

1) Consider using a JVM System property that sets the environment of the machine (e.g. "my.env=TEST"), telling the configurer which property file to use. For example:

  <context:property-placeholder
      location="classpath:db-${my.env}.properties"/>

If the "my.env" property was set to "TEST", then obviously the PropertyPlacementConfigurer would look for a file called "db-TEST.properties". For Tomcat, this property can be set in the admin console or defined in a startup script (e.g. "-Dmy.env=TEST") - neither of which is very elegant. Alternatively, it is possible to use JNDI with Tomcat, defining "my.env" in the server.xml and the context.xml of the web app. (Note, there are of course many other ways to solve this environment-specific problem, but this is an easy and relatively straight-forward one.)

 

2) It may be necessary to set the ignoreUnresolvablePlaceholders to true for any PropertyPlaceholderConfigurer, which will ensure that a configurer won’t fail if it can’t find a property. Why would this be a good thing? Oftentimes, one context file will import other context files, and each may have their own configurer. If ignoreUnresolvablePlaceholders is set to false (the default), then one configure would fail if it couldn’t find the property, even if another configurer down-stream could find it (see good explanation here). Beware, however, since this will suppress warnings for legitimate missing properties, making for some tough-to-debug configuration problems.

 

3) To encrypt properties, subclass the PropertyPlacementConfigurer and override the convertPropertyValue() method. For example:

protected String convertPropertyValue(String strVal) {
  //if strVal starts with “!!” then return EncryptUtil.decrypt(strVal)
  // else return strVal
}

4) Consider using the systemPropertiesMode property of the configurer to override properties defined in property files with System properties. For one-off environment specific properties this can be a helpful solution, however, for defining many properties, this configuration can be cumbersone.

 

5) For properties that need to be managed outside of the WAR, consider using a System property to define where the file is located. For example, the property ${ext.prop.dir} could define some default directory on the file system where external property files are kept:

<context:property-placeholder
     location="file:///${ext.prop.dir}db.properties"/>

This entails, however, that this property is set for any process that leverages the Spring container (e.g. add the param to the Run Configuration for integration/unit tests, etc.), otherwise the file would not be found. This can be a pain. To circumvent, the configurer can be overridden – changing the behavior such that it looks to the external directory only if the System property is set, otherwise it pulls from the classpath.

 

6) Beware of redundancy of environment-specific properties. For example, if the solution is to have one property file for each environment (e.g. “db-test.properties”, “db-dev.properties”, etc.), then maintaining these properties can be a bit of a nightmare - if a property "foo" is added, then it would have to be added to the property file for each environment (e.g. DEV, TEST, PROD, etc.). The PropertyOverrideConfigurer is appropriate to eliminate this redundancy, setting the default value in the application context itself, but then the overriding value in a separate file. It's important, however, to document this well, since it can look a bit "magical" to an unsuspecting maintenance developer who sees one value specified in the context file, but another used at runtime.

Conclusion

Managing properties for an enterprise application is a little trickier than one might expect. With Spring's property configurers, however, the toughest part is just knowing what you need - the rest comes out of the box, or with some minor extensions.

Hopefully a few of these tips will be useful for you. Please let me know some of your own!

I believe that software development is fundamentally about making decisions, and so this is what I write about (mostly). I've been building software for about 20 years now, as a developer, tech lead, and architect. I have two degrees from Carnegie Mellon University, most recently one in philosophy (thesis here). I live in Pittsburgh, PA with my wife, 3 energetic boys, and dog. Subscribe here or write me at ben dot northrop at gmail dot com.

Got a Comment?


Sign up to hear about the next post!

If you liked this article and want to hear about the next one, enter your email below. I don't spam - you'll only receive an email when there's a new post (which is about once a month, tops). It's all low-key, straight from me.

Comments (43)

Jeff Johnston
September 29, 2009

I started a project that people may be interested in. It is called Configleon and solves the problem of loading property attributes in different environments and/or server contexts. With Configleon you can build one war file that can be deployed to every location.
Configleon really shines is in its ability to cascade the property attributes. This allows all the common attributes to be defined in a global file and then overridden for each application server context.
http://code.google.com/p/configleon/
Jim
November 09, 2009

Ben, the tips you mentioned were extremely useful. Thanks a lot.
Ben
April 16, 2010
Ben, I don’t want Spring to load my properties file as I want to check it and reload it if it changes, so my semantics are more complex than what Spring offers.
However, what I want to do is to pass in name of properties file location (using absolute path), via a system property, ala:
Using system properties in this way does not seem to work, spring only supports system properties *within* properties placeholder config….
Ronald
July 06, 2010
Another option is to use multiple propertie files, one in the war and one in your home directory and override (if required) certain settings in the properties file in your home dir, for instance the db connect string can be defined in both files. If you put your home properties file as last, then the settings in that file will override the original ones:
classpath:/someApp.properties
file:${user.home}/someApp.properties-->

The ignoreResourceNotFound will skip the setting for user.home if it is not found. Thus it will also run in a test environment where that file is not available.
Ronald
July 06, 2010

well the code tag didnt help so, lets try it like this:


classpath:/competities.properties
file:${user.home}/someApp.properties



Mike Gage
September 08, 2010
Great tips. Thank you!
Vishwas
September 19, 2010
Thanks Ben! Just what I was looking for
Anil
September 30, 2010
Beautiful tips from Ben. Thank You.
I do have one question – so does this mean we can’t use the spring if we need the property to be updated at runtime (ie. dynamic)?
Thanks
Anil
Ben
September 30, 2010
Thanks Anil! Good question…and to be honest, I don’t know the answer completely.
If you have properties that need to be updated at run-time, my sense is that the PropertyPlaceholderConfigurer is not what you’re looking for…since this will inject properties into beans at the time the application context is loaded.
What I’m unsure of…is if you have some bean defined in Spring as “prototype” scope…which has some properties injected into it from some property file (via the PropertyPlaceholderConfigurer)…whether (a) when this bean is instantiated Spring loads afresh the property file and injects this property or (b) Spring uses the property values as they were at application start-up to inject into that bean. It’s a great question though…and when I get a free minute, I’ll test it out and get back to you.
In general though, if you have dynamic properties, you may want to just consider a simple ResourceBundle…or maybe just externalize these properties to a database (if possible).
Hope that helps!
donn
October 08, 2010
nice tips. Thanks.
In case you have tested out the dynamic loading of properties, please let us know.
thanks again.
Ben
October 08, 2010
So…it turns out that dynamic properties using the PropertyPlaceholderConfigurer doesn’t work, even with a prototyped-scope bean.
I ran a quick test…and it seems that property values are cached from the time the application context is loaded. Even if you change a given property value in the property file after the application starts, your bean will still be injected with the property value that was initially loaded.
If you’re interested, here’s the test I ran: SpringPropTest.zip.
Tarun
October 13, 2010
Is there a way to log the resolved values of all the properties? I have the same properties defined in different properties files and i want to know which is the finally resolved value of the property.
Also : For Dynamic Properties, I found the the apache-configuration framework very usefull.
Ben
October 13, 2010
Hi Tarun. Yeah…try subclassing the PropertyPlaceholderConfigurer, like this::

public class LoggingPPC extends PropertyPlaceholderConfigurer {
@Override
protected void loadProperties(Properties props) throws IOException {
super.loadProperties(props);
for (Entry entry : props.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
Then use this class when you load properties:


...


Hope that works!
Tarun
October 13, 2010
Thanks Ben, it works just fine :) , great help
Anil
October 21, 2010

Thanks Ben for testing it out. In fact i also tried and has concluded same (dynamic property update may not work with Spring).
I saw Tarun mentioned that “the apache-configuration framework” works fine. Can you give some more tips on that please? An example how it works or reference to any website?
Sharath
October 25, 2011
Hi Ben,
Thanks for all the tips.
I actually have a requirement that I have to use the property file external to the war; I am trying to use the external file location in the property-placeholder
eg:
After this code I have a code configuration in my xml which uses the property within the Sample.properties
The code fails as it is not able to fetch the values from the property-placeholder; it fails at war deployment as the xml files I use are used during war deploying.
can you please help in this regard.
Gabriel
January 10, 2011
Is there a way of getting a default value if the system property is not set?
For example in this line of code you wrote,
if -Dmy.env parameter is not passed it will blow up, is there a way to tell Spring that if that property is not set, then use a default value (E.g. dev)
so it will get resolved in something like this:
I read time ago that using :value after the variable name will do it, but it does work, for example like this
Any suggestion?
Ben
January 10, 2011
Yeah, definitely…check out this:
http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html#setSystemPropertiesMode(int)
Basically, if I understand your question correctly, you can set the systemPropertiesMode and set it to “2″ (override), and it should pick up the System property first, and if it’s not there, get the property normally.
It’s also a very powerful fall-back solution to sub-class PropertyPlaceholderConfigurer in cases where you need to do really tricky things.
Leena
January 21, 2011

is it possible to load a property xml using ?
gsathya
January 21, 2011
Hi
is it possible to use nested properties like this and use @value annotation to set the values.
########################################
schema.name=report
select.query=select * from ${schema.name}.user
########################################
public @Value(“#{query['select.query']}”) String selectQuery;
** When i print the value of selectQuery the same string is printed , without interpreting the place holder value
Andy B
February 20, 2011
Thanks for this write-up, very useful.
In Spring 3.0 you can set default values for placeholders. e.g. ${env:local} where ‘local’ is the default value if ${env} is not resolved.
This is useful for if you’re setting a system property to resolve a placeholder, e.g the environment, but in development you can just fall back to the locally defined default value.
Ben
February 21, 2011
Thanks very much Andy! When I wrote this post I was using Spring 2.5, so I’ll swing back and incorporate this into my post.
Wendy
February 22, 2011
Hey.
I’d like to thank you for this post.
This has been very useful for me !
Joshua Smith
May 25, 2011
Very useful post. Thanks.
I was successful switching things out with environmental variables, but not using JNDI properties when running in tomcat. I can print out the JNDI properties in a JSP and they are set fine, but Spring doesn’t seem to find them and so it defaults to what is in the war file.
This what I put in my TOMCAT_HOME/conf/context.xml file:
This is what I have in my application context:
And the following in my application context:

The goals is that it uses JNDI variables to resolve the property files if they are available (which is when it’s running in Tomcat). It uses the environmental variables if they are available (when it’s running as a stand-alone Java application). And it uses the properties files in the JAR/WAR file if the others are not found. All of that works fine except the JNDI properties.
Any ideas?
Thanks,
Joshua Smith
Joshua Smith
May 25, 2011
The blog software ate my XML. I’ve posted the snippets here:
http://www.rationalpi.com/spring/snippetfromContextDotXmlFile.txt
http://www.rationalpi.com/spring/snippetfromApplicationContext.txt
Rippon
July 15, 2011
Thanks for the article.
But I tried reading the properties from the disk e.g If I want to load the properties from C:\projects
I tried using
But it is not working..
Any help will be appreciated.
alsky
July 16, 2011
Thank you mate, you made my day.
java guy
August 29, 2011
Thanks, you made my day * 2
Abdulkadir
September 16, 2011
Thank you very much, you saved my day.
Kurosaki
September 17, 2011

Hi , cool , please can you make exmaple of any scenrio/option you mentioned using Spring 3 ?
encrypt part wasn’t so clear ,
and genral question , why to use properties file at all ? it’s just another file , we can use Spring 3 XML property definition and use EL expression for example …. and why to make more than 1 file ? why not merge all into 1 file?
Thanks
Asif
October 09, 2011
Hello Ben, thanks for this great help article. Can you please suggest something about my below problem. I was trying to load the environment variable from another property file.
I am try to do as below. Does this have any problem? Although I get the error that ${app.env}.properties is not found why is this so. Thanks.
The env.properties file has this
app.env=app.test
Jasper
October 30, 2011
Can anyone PLEASE help me with this question:
http://stackoverflow.com/questions/7940452/spring-application-context-not-able-to-load-property-placeholder-properties
November 14, 2011
Finally what is the conclusion of dynamic property binding in spring3? Any one got solution? My application needs to refer some property files on login action rather than application start up.Please let me know if any of you has a solution.
Nik
December 05, 2011
Hey, Ben!
You made my day! (or two)
Thank you very much!
Maybe it will be useful for someone.
If you want to transfer you property from main argument (System[] args) to spring application context xml file, do following:
1. in your xml file use your property
Example:
(bean …)
(property name=”logFileName” value=”${my.env}” /)
(/bean)
2. in main() add this line
System.setProperty(“my.env”, args[0]);
3. Done! It was easy.
Attension: On next launch of program, if you delete setProperty(“my.env… line, this property will be null.
Nagababu
December 28, 2011
hey ben,
Can we configure the application-config-file based on user selection in GUI lavel.
for example if i have combo box with some specified options like 1,2,3
if i select 1 our application use the configfile1 to connect db
please give the reply as soon as possible.
Ben
December 30, 2011
Thanks everyone for the feedback! I’m glad this post has been helpful.
Also, I’m sorry (Nagababu, etc.) that I haven’t replied to specific questions. Maybe StackOverflow would be a better forum for quicker feedback? Thanks again.
Kenny
January 25, 2012

Thanks Ben,its really helpfull
As i want to keep my .properties file out side src folder(to exclude it from jac)
now i gave a code of
(filemanage is prjct name)
here i am getting an exception of could nt load properties nested exception
did i give anything wrong here
Any help will be appreciated
Thanks
shashr
January 25, 2012

Hi Ben…Thank you so much for this wonderful article.
Joshua , This link may be helpful for you
https://jira.springsource.org/browse/SPR-3030
Bhasker
January 30, 2012

Thanks Ben, it really helpd me…
Tarun
February 12, 2012
Thanks a lot Ben. This was really helpful.
Nic
October 03, 2012
Hi
Tomcat server.xml is configured:
In applicationContext.xml I have:
to result to classpath:META-INF/spring/dev/*.properties
When starting tomcat, the properties files can’t be located.
Spring exception with error:
Could not resolve placeholder ‘database.driverClassName’ (which is a property in database.properties)
Am I missing something?
Should ${server_name} be resolved to ‘dev’ by just using ?
Thanks
Nic
Georg
January 09, 2013

Thanks Ben, I’d like to know what you (or anybody else) think about an additional option to set “environment specific” properties. I was thinking about using a system environmental variable what could be easily accessed with Java 5 ‘System.getenv()’. This would be a very simple way to access a ‘machine specific’ property.
For instance, by using something like ‘System.getenv(“MY_APP_HOME”) + my_app_properties.properties’ I could access different machine dependent file by setting MY_APP_HOME on my machines. This would be helpful for instance when switching from a windows based development environment to a Linux based production one. I’m sure that Spring offers some nice ways to access the environmental variables as well.
anand
July 02, 2013

hi
I am not able to reload properties file dynamically if any sample code .Please provide me