Project Configuration with Spring
Join the DZone community and get the full member experience.
Join For FreeTable of Contents
- 1. Overview of the problem
- 2. The .properties files
- 3. Spring configuration
- 4. Setting the Property in each environment
- 5. Maven and testing
- 6. Going further
- 7. Conclusion
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>
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.Opinions expressed by DZone contributors are their own.
Comments