Using the Spring PropertiesFactoryBean to Clean Up Your Config Files

by Jens Alm

In Spring Framework there is a very handy tool for using property based configuration files called PropertiesFactoryBean. It can easily be your best friend when it comes to using config files to govern behavior in your application. I recently helped a client clean up their config file situation and this is how it was done.

What is Spring Framework?

Spring Framework is an open source framework that makes life easier for most developers and was originally created as a counterpoint to the bloated J2EE architecture that was prevalent during the early part of this millennium. Spring provides dependency injection along with a flexible way of creating the infrastructure for most applications. It provides support for handling transactions, databases, proxying, messaging, MVC, etc. Spring also has multiple sub-projects that provide support for additional integration.

How I Found It

When I arrived at my current client they already had an application context set up with a PropertiesFactoryBean reading a different property file for each environment that the code should run in. This was done by adding a system property on the command line.

run.sh -DENV=preprod

By adding the ENV=preprod Spring knew through the way the application context is set up to use the config.preprod.properties file. It knew this because the relevant part of the configuration file looked like this.

<> id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <> name="location">
    <>>/WEB-INF/properties/config.#{systemProperties[‘ENV']}.properties>
  >
>

Let's assume that we have 3 different property files for configuration: prod, preprod and dev. Each file has a few entries concerning how the application should behave. For example the config.prod.properties could contain something like this:

search.engine.host = prod_search.company.com
search.engine.port = 1234
search.max.results = 25
search.timeout = 5
search.username = prod
search.password = super_secret_password

Each of the config.*.properties contain all these properties with varying values depending on environment.

Using Springs @Value annotation we can easily access each config value painlessly.

@Value("#{configProperties['search.engine.host]}")
private String searchEngineHost;
 
@Value("#{configProperties['search.engine.port]}")
private String searchEnginePort;

This all works and is pretty easy to use but we can make it better.

How It Was Changed

First we would modify the application context like this.

<> id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
  <> name="ignoreResourceNotFound" value="true"/>
  <> name="locations">
    <>>
      <>>/WEB-INF/properties/config.prod.properties>
      <>>/WEB-INF/properties/config.#{systemProperties[‘ENV']}.properties>
    >
  >
>

Notice the change from location to locations and the addition of a list of resources instead of just the one resource file. We also added the prod config file as the first file to read. What this provides us is the possibility to override config properties instead of having to repeat them. Take a look at the config property files after modification.

config.prod.properties (same as before)

search.engine.host = prod_search.company.com
search.engine.port = 1234
search.max.results = 25
search.timeout = 5
search.username = prod
search.password = super_secret_password

config.preprod.properties

search.engine.host = preprod_search.company.com

config.dev.properties

search.engine.host = localhost
search.engine.port = 4321
search.username = dev
search.password = not_so_very_secret_password

With prod acting as a fallback for all values not specified we can omit any values we don't want to change.

In our preprod environment we get all the same values as in prod except for the search.engine.host property which is overridden. In dev we override most values but leave search.timeout and search.max.results the same as prod.

If no -DENV system property is added on the command line then all that Spring will read is the prod file. The ignoreResourceNotFound is the important part for this to work without errors being reported on start up.

Conclusion

With small config files like these examples the benefit is not as obvious as it would be in a project with 500 lines of property files. Our prod file still has the 500 lines of properties but most of our other environment config files have anywhere from 10 to 50 properties because we rely on mostly the same config settings as we do in production.