DevOps Zone is brought to you in partnership with:

I’m a software engineer with a passion for REST, TDD and clean code, Web Security and Data Mining. Baeldung is about all of these and more. Eugen is a DZone MVB and is not an employee of DZone and has posted 20 posts at DZone. You can read more from them at their website. View Full User Profile

Project Configuration with Spring

04.16.2013
| 3844 views |
  • submit to reddit

Table of Contents

1. Overview of the problem

Being able to set up some configuration that is specific to the environment the application runs on is something that most projects have to solve one way or another. For a Spring application there are several alternatives for addressing this problem, varying from simple and flexible solutions all the way to absolute nightmares of unnecessary abstraction.

One of the more straightforward ways to address the problem in a flexible and manageable way is to use properties files and the first class property support provided by Spring. As a proof of concept, for the purposes of this article, I will discuss the configuration of persistence in an application.

In this case, the properties will represent database credentials and URIs – for instance, we will want to be able to go to a production database in the production environment and to an in memory database for the dev environment. Other persistence related configuration may be the Hibernate dialect in case the application is using Hibernate or the jpa dialect for JPA – these should actually be sufficient to switch between persistence providers completely.

2. The .properties files

Considering the following types of environments that we want to cover – dev, staging, production – we will need to create the following properties files: persistence-dev.properties, persistence-staging.properties and persistence-production.properties. In a typical Maven application, these can reside in src/main/resources, but the wherever they are, they will need to be available on the classpath when the application is deployed.

Since all properties files will be under version control alongside the rest of the codebase, all environment configurations will be transparent and fully reproducible. This comes in extremely handy in cases where a specific production environment must be quickly reproduced so that an issue can be debugged or verified.

3. Spring configuration

In Spring, the correct properties file needs to be used based on the environment:

<?xml version="1.0" encoding="UTF-8"?>02.<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04.xmlns:context="http://www.springframework.org/schema/context"
05.xsi:schemaLocation="
06.<a href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans<;/a>
07.<a href="http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">http://www.springframework.org/schema/beans/spring-beans-3.1.xsd<;/a>
08.<a href="http://www.springframework.org/schema/context">http://www.springframework.org/schema/context<;/a>
<a href="http://www.springframework.org/schema/context/spring-context-3.1.xsd" "="">http://www.springframework.org/schema/context/spring-context-3.1.xsd"</a>>
 
<context:property-placeholder location="
classpath*:*persistence-${envTarget}.properties" />

</beans>
If Spring 3.1 is used, this configuration will create a PropertySourcesPlaceholderConfigurer which will add the properties defined in the file to the Spring Environment abstraction. For older versions of Spring, the older PropertyPlaceholderConfigurer will be created for dealing with the properties. For more details on the newly introduced Environment abstraction and properties support, see the previous Properties with Spring article.

This approach allows for the flexibility of having multiple *.properties files for specific, focused purposes – the persistence related properties can be grouped together in their own persistence-*.properties file, while other concerns can have their own .properties files. The common properties that are global to the application but do not change based on the environment can simply be added in an unique common.properties file.

4. Setting the Property in each environment

The final, deployable war will contain all properties files – for persistence, the three variants of persistence-*.properties. Since the files are actually named differently, there is no fear of accidentally working against the wrong one – by setting the envTarget variable, we will strongly select a single instance of the multiple existing variants.

The envTarget variable can be set in the OS/environment or as a parameter to the JVM command line:

-DenvTarget=dev

5. Maven and testing

Some integration tests need to have persistence enabled, but obviously not the same provider/schema as a standard environment. The flexibility of the current solution is perfect for this use case – the Maven pom.xml will need to simply specify the envTarget variable for testing:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
      <systemPropertyVariables>
         <persistenceTarget>h2_test</persistenceTarget>
      </systemPropertyVariables>
   </configuration>
</plugin>
The corresponding persistence-h2_test.properties file can be placed in src/test/resources so that it will only be used for testing and not unnecessarily included and deployed with the war at runtime.

6. Going further

There are several ways to improve on this solution if needed. One such way is to use a more complex encoding for the names of the properties files, specifying not just the environment in which they are to be used, but also more information (such as the persistence provider).

The names of the properties files should now be: persistence-h2.properties, persistence-mysql.properties or, even more specific: persistence-dev_h2.properties, persistence-staging_mysql.properties, persistence-production_amazonRDS.properties.

The advantage of such a naming convention – and it is just a convention as nothing changes in the overall approach – is simply transparency. It now becomes much clearer what the configuration does only by looking at the names:

  • persistence-dev_h2.properties: the persistence provider for the dev environment is a lightweight, in-memory H2 database
  • persistence-staging_mysql.properties: the persistence provider for the staging environment is a mysql instance
  • persistence-production_amazon_rds.propertie: the persistence provider for the production environment is Amazon RDS

7. Conclusion

This article discusses a flexible solution for doing environment specific configuration in Spring. For a complete configuration using this method, check out REST github project.

If you read this far, you should follow me on twitter here.
Published at DZone with permission of Eugen Paraschiv, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Andrew Gilmartin replied on Sat, 2013/04/20 - 10:07am

We added a further twist to the properties and added "conditional sections" to the contexts.

For properties, we have the normal "common" properties that define the default values for all properties for all deployments, deployment specific properties that override the defaults, and archetype specific properties that (mostly) enable conditional sections. Examples of archetypes are "full text search", "full text indexing", "analytics processing", "upload processing", etc. 

The conditional sections allow for the inclusion of beans based on the value of a property. We have many properties that have names of the form "xxxx.enabled". When the value is "true" then the conditional section's beans are defined. (A similar effect can be had by using different "application" context files but we found that conditional sections worked better for us.)

The startup procedure is to 

  1. load the common properties to "prime" the environment, 
  2. load the deployment specific properties where are defined the archetypes used by the deployment, 
  3. load each of the archetype properties, and then, finally, 
  4. reload the deployment specific properties again (to reset deployment specific property values). 

Together these two features -- conditionals and archetypes -- allows us to deploy a specific configuration with very little customization. And it is all done within Spring with just two custom tags.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.