As a proof of concept, for the purposes of this article, we’ll take a look at one specific type of property – the database configuration. It makes perfect sense to use one type of database configuration for production, another for testing and yet another for a dev environment.

2. The .properties Files for Each Environment

Let’s start our Proof of Concept – by defining the environments we want to target:

Dev

Staging

Production

Next – let’s create 3 properties files – one for each of these environments:

persistence-dev.properties

persistence-staging.properties

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.

An important sidenote – having all properties files under version control makes configuration much more transparent and reproducible. This is in opposition to having the configs on disk somewhere and simply pointing Spring to them.

This approach allows for the flexibility of having multiple *.properties files for specific, focused purposes. For example – in our case, the persistence Spring config imports the persistence properties – which makes perfect sense. The security config would import security related properties and so on.

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 including the wrong one. We will set the envTarget variable and thus select the instance we want from 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. Testing and Maven

For integration tests that need persistence enabled – we’ll simply set the envTarget property in the pom.xml:

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 build additional flexibility into 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). For example, we might use the following types of properties: 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. An alternative solution using profiles can be found here.

The implementation of the solution can be found in the GitHub project – this is a Maven-based project, so it should be easy to import and run as it is.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2: