Table of Contents

1. Configuration Must Be Environment Specific

Configuration must be environment specific – that’s just a fact of life. If that weren’t the case, then it wouldn’t be configuration and we would just hardcode values in code.

For a Spring application there are several solutions you can use – from simple solutions all the way to uber-flexible, highly complex alternatives.

One of more common and straightforward solutions is a flexible use of properties files and the first class property support provided by Spring.

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

720

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.

3. The Spring Configuration

In Spring, we’ll include the correct file based on the environment:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-4.0.xsd">

      <context:property-placeholder
         location="
         classpath*:*persistence-${envTarget}.properties" />

</beans>

The same can of course be done with Java configuration as well:

@PropertySource({ "classpath:persistence-${envTarget:dev}.properties" })

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:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
      <systemPropertyVariables>
         <envTarget>h2_test</envTarget>
      </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 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.

Course – LS (cat=Spring)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!