Environment-Specific Configuration of Spring Applications

Over and over I see projects struggling with the problem of parameters in property files that change in different environments; after all that’s pretty much the idea with the property files anyway – to make it easy to reconfigure the system.

The PropertyPlaceholderConfigurer lets us externalize configuration parameters from the XML configuration to property files, and that’s excellent, but I’ve seen (and implemented myself) so many different cumbersome attempts on environment configuration it’s not even funny.

The problem is this: We’ll want to have one test-environment version of the property file bundled with the application source code to simplify starting the app in test mode from inside the IDE. So how do we reconfigure the application for production? Extract the war file, replace the property file with the production version, and re-pack the war? No, we really want to avoid this. Another, even worse solution is to have a number of different versions of the property files and then using different build profiles including the “correct” versions.

As it turns out there’s a perfectly simple, obvious, but surprisingly hard-to-google solution to this problem: You probably know that it’s possible to specify several property files when configuring the PropertyPlaceholderConfigurer; well it turns out that a property redefined in a later file will override a setting from a previous file. This allows us to do the following:

Note the ignore-resource-not-found attribute, which is needed to so that not all files need to be in place. Now consider that the bundled property file, WEB-INF/myApp.properties has the following contents:

and that there is no file at /etc/myApp/myApp.properties on your development machine. When we start the application in the IDE, it will load and run with the test settings.

If we now place an environment-specific property file at /etc/myApp/myApp.properties with the following contents:

these are the settings that will be used when the application is started on that machine. This is what we’ll do on the production machine. And what’s even better: it won’t even be your responsibility – you just need to document where the property file should be placed and which properties that can be specified and then leave it for operations to actually make it so.

Simple as that.

This Post Has 7 Comments

  1. Thanks for the tip! But what if you need to change the configuration at runtime? Perhaps store it in the database (it’s not changed after reboot)?

  2. It’s important to note that the PropertyPlaceholderConfigurer works on bean definitions, before any beans are actually created. This means that it wouldn’t make any difference where the configuration parameters are placed; any change to them still wouldn’t be applied until the ApplicationContext is restarted.

    The standard solution to enable tweaking of application configuration in runtime would be to expose the bean using JMX. You can then use e.g. JConsole to set Attributes on the exposed MBean.

    Spring makes it really easy to expose any bean over JMX, check the reference documentation for details.

  3. You gotta love Spring.

    I used this technique on earlier projects, it works great!
    Nice that it is now Googlable ;-) – thanks Mattias.

  4. One problem I see with this approach is when you’ve multiple env specific properties (other than just test and prod). e.g. qa , qa1 etc.

  5. Can you specify three locations for three environments such as:

    location=”WEB-INF/dev/myApp.properties,WEB-INF/staging/myApp.properties,WEB-INF/prod/myApp.properties”??

    Thanks,

Leave a Reply

Close Menu