Last Update: 14.03.2018. By Jens in Spring Boot | Newsletter
I covered properties handling in Spring Boot a while ago in my Learnletter. This page summarize all emails to make it easier for you to dive into the topic.
Spring makes it easy to inject configuration values from outside the code. Simple use the @Value annotation on a field and define the name of the property like:
@Value("${myProp}")
private String myProp;
${} indicates a statement using the Spring Expression Language (SpEL). It will lookup for a property in the PropertySource. This one usually, will check include properties from property files, env variables, and system variables.
It is auto-configured in Spring Boot and will include the application.properties and _application.yml_and of course env and system variables. If we define our property at any of these places, it will be found. If not, an Exception will be thrown.
We can ürevent that by adding a default value. We do have two alternative ways.
First, we could just declare it in the application.properties with the default value. In case we want to override it, we just define it as an env, system or program variable. Those win over the property file.
Second, we could define the default value already in the @Value annotation by adding a _ :_ followed by the default value as a suffix to the property name like:
@Value("${myProp:myDefault}")
private String myProp;
In this case, Spring will use the default value, if it did not find any declaration of it in the PropertySource.
Properties in Spring are not limited to Strings. Sure, they are in the property file, but not necessarily as a field in our class. Whatever type we use, Spring will try to convert the string value from our input to the correct type.
For example with a boolean:
@Value("${myProp}")
private boolean myProp;
We can set the value now like:
myProp=true
Or:
myProp=false
It doesn’t matter what type we use as long as Spring has a converter for it. It covers the most common cases. If not, we can plug in our own, but honestly, I never had the need for that.
Using @Value to inject properties is fine as long as it is just a handful. When we have more, and they are grouped around a single configuration entity like all props for a remote connection, we can introduce a configuration class using the @ConfigurationProperties annotation of Spring Boot.
We can mark a simple POJO with it and Spring Boot map properties to fields of the class.
@ConfigurationProperties("cb")
public class CBProperties {
private boolean enabled;
private int timeout;
private String host;
// standard getters and setters
}
The parameter @ConfigurationProperties accepts, is the prefix for our properties. The keys of the example above look like:
We can inject this class like any other Spring Bean.
However, before we can use this feature, we must enable it on one of our @Confiuration classes by adding the @EnableConfigurationProperties annotation and give it the name of our config property class like:
@Configuration
@EnableConfigurationProperties(CBProperties.class)
public class MyConfiguration {
}
Voila!
Nice, isn’t it? And it even supports nested classes.
We can also use placeholders in properties. A placeholder is a simple reference to another defined property, like a variable.
Let’s see it in action:
my.host=localhost
my.url=http://${my.host}/remote-call.whatever
The placeholder has the same syntax as the expression in the @Value annotation. It’s SpEL after all.
So, the value of my.url will be http://localhost/remote-call.whatever.
However, don’t overdo it. If it gets too complex, it will be hard to maintain - there is no compile time error.
When we start to define properties, sooner than later, we are facing the problem of having environment specific ones like DB connections, paths in the filesystem, etc.
Spring offers us a solution in the form of profiles. A profile is not tied to a system environment like dev, preprod, and production. It is an arbitrary identifier we can use to split up configuration.
However, a usual case is splitting up by runtime environment. Profile specific properties are using the naming convention:
application-{profile}.properties
They are placed along the regular application.properties and the same rules apply. When we activate multiple profiles, and the same property key is declared more than once, it will use the last one found.
A common way to activate a profile is by specifying it on the command line with –spring.profiles.active= , followed by a comma-separated list of active profiles, so for example, if we want to activate the profiles local and db it looks like:
--spring.profiles.active=local,db
Using –spring.profiles.active is not the only way to set the active profile. Reader Sandeep came up with an excellent question:
Let’s assume that I have three environments: Dev, Staging, and Prod. I will create three property files, one for each environment like application-dev.properties, application-staging.properties, and application-prod.properties. I understand the concept until this point. Now, let’s say I am deploying this on three different servers with Jboss EAP (Wildfly) for each environment, how will I set up the active profile? Could you please help me understand this.
Basically, we have three possible ways to do that. They also work for modern Spring Boot deployments, not just for the war-style.
Adding it as a VM system property when starting the Java process like:
java -jar Whatever.jar -Dspring.profiles.active=preprod
Include a regular application.properties and set the active profiles in it with
spring.profiles.active=preprod
However, we need to set the particular value somewhere in the build and deploy pipeline. A classic way would be to use a Maven property placeholder in the property file and let Maven filter it. Again using profiles, but this time it is Maven profiles. So, during a preprod b&d, we use a Maven Profile which sets the Spring property spring.profiles.active.
I’ve used all variants in the past, but if it’s possible, I will go with No. 2. It’s the smoothest and fastest way with the lowest implications, at least when operations are willing to do it…