Configuring Spring Boot applications

This tutorial demonstrates how to use Spring Boot’s built-in configuration capabilities, including which are the available formats for configuration and how to inject properties from your configuration sources.

Spring Boot configuration

Spring Boot has several options for storing your application properties and configuration:

  • Store properties in the file application.properties
  • Use a YAML file application.yml
  • Use environment variables. This option is becoming a standard for cloud based applications, for example if you are running Spring Boot on Openshift
  • Finally, you can still use command-line arguments. (e.g. -Dproperty=value)

Let’s begin with properties defined in the app’s application.properties file and work our way up.

Injecting properties with @Value

Firslty, we will create a simple Spring Boot project with a minimal set of dependencies:

spring init -g=com.masterspringboot -a=spring-boot-config --package=com.masterspringboot -x

This command will create a basic Maven Java project that runs a Spring Boot Application. Now go to your project and edit the file DemoApplication.java:

package com.masterspringboot;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemoApplication {
  private static Logger log = LoggerFactory.getLogger(DemoApplication.class);

  @Value("${name}")
  String username;

  @Bean
  CommandLineRunner values() {
    return args -> {
      log.info(" Name is: " + name);
    };
  }

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

As you can see, we have added a Logger to print out our environment variable. Then, we are injecting with the @Value annotation the Property “name”. Finally, we will output this property within a CommandLineRunner block.

java.lang.IllegalArgumentException: Could not resolve placeholder

As it is, the application will not build because Spring Boot is not able to resolve the property “name” with a default value. So you should either set a default value in the @Value expression or define the property in a configuration file.

Therefore, we will configure the name property in application.properties. You need to place the file in the following directory tree;

src
├── main
│   ├── java
│   │   └── com
│   │       └── masterspringboot
│   │           └── DemoApplication.java
│   └── resources
│       └── application.properties
└── test
    └── java
        └── com
            └── masterspringboot
                └── DemoApplicationTests.java

Edit the file application.properties and set a value for “name”:

name=Frank

Next, build your application with:

mvn install spring-boot:run

Here is the output that confirms the System property injection:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.4)

2022-03-01 10:13:41.851  INFO 29375 --- [           main] com.masterspringboot.DemoApplication     : Starting DemoApplication v0.0.1-SNAPSHOT using Java 11 on fedora with PID 29375 (/home/francesco/tmp/boot/target/spring-boot-config-0.0.1-SNAPSHOT.jar started by francesco in /home/francesco/tmp/boot)
2022-03-01 10:13:41.853  INFO 29375 --- [           main] com.masterspringboot.DemoApplication     : No active profile set, falling back to 1 default profile: "default"
2022-03-01 10:13:42.247  INFO 29375 --- [           main] com.masterspringboot.DemoApplication     : Started DemoApplication in 0.697 seconds (JVM running for 1.013)
2022-03-01 10:13:42.251  INFO 29375 --- [           main] com.masterspringboot.DemoApplication     :  Name is: Frank

Changing the default name or location for your Spring Boot application.properties file

Spring Boot searches for the configuration files (application.properties or YAML file) in the following order:

  • The /config subdirectory located in the current directory
  • The current directory
  • A classpath /config package
  • The classpath root

Remember that you should already have a application.properties file in the classpath root ( src/main/resources ).
In order to change Spring Boot default name for the property file, then pass the -Dspring.config.name as argument as in the following example:

mvn spring-boot:run -Dspring.config.name=myconfig.properties

Overriding Properties from the Command Line

Spring Boot application are also able to pass Properties from the Comman Line (-D options). When you do so, these properties take precedence over those stored in application.properties.

As proof of concept, run your application again passing the property name on the Command Line:

java -Dname=John -jar target/spring-boot-config-0.0.1-SNAPSHOT.jar

Then, check that the Property name is now “John”:

spring boot configuration

Using Place holders for properties

You can also derive the value of a property from another. For example, we will derive the value of “name” from “nickname”. Here is how to nest the two properties in application.properties:

nickname=Fred
name=${nickname}

You can do the equivalent also in the @Value annotation:

@Value("${name: ${nickname} }")
String name;

Default values for your Properties

By default, if you try to inject a property which is missing, an IllegalArgumentException is thrown:

// Throws IllegalArgumentException ! @Value("${wrong.property.name}")

You can however set a default value for your properties so that, when you attempt to inject it and the value is missing, a default value is provided by adding a colon between the Property name and the default value:

@Value("${welcome-message:Hello world}")

The Injected Property is null

A common pitfall for Spring Boot newbies is that they try to use the injected properties before a Bean has been created. For example:

@Service class SampleService {
  @Value("${welcome-message:Hello world}") private String message;
  // ...      
  SampleService() {
    System.out.println(message);
    // null!    
  }
}

As you can see, in the above example we try to reference the @Value from the Bean constructor we get a null because Spring needs to first create instance of class (call the constructor) and then inject values to the fields.

Also, it is worth to know that you can’t use @Value on static variables. You’ll have to either mark it as non static or have a look here at a way to inject values into static variables:

Using @ConfigurationProperties

Using @ConfigurationProperties, a developer can define properties, group related properties, and reference/use them in
a tool-verifiable and typesafe way. Let’s understand this with an example:

@ConfigurationProperties(prefix="person")
public class Person {

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getSurname() {
    return surname;
  }
  public void setSurname(String surname) {
    this.surname = surname;
  }
  String name;
  String surname;
}

In order to register Person to manage configuration properties, I have added the @ConfigurationProperties annotation and specified the prefix to use for all Person properties.

Within our Main application Class, we will inject the Person as a Bean and then use one of its properties:

@SpringBootApplication
@ConfigurationPropertiesScan
public class DemoApplication {
  private static Logger log = LoggerFactory.getLogger(DemoApplication.class);

  private Person person;
 

  @Autowired
  public void setPerson(Person person) {
      this.person = person;
  }
  
  @Bean
  CommandLineRunner values() {
    return args -> {
      log.info(" Name is: " + person.getName());
    };
  }

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

To complete the example, let’s define the properties for Person, using “person” as prefix:

person.name=Mark
person.surname=Spencer

If you run again the application, you will see that the property has been injected from application.properties into the Person Bean:

2022-03-01 12:07:36.722  INFO 35573 --- [           main] com.masterspringboot.DemoApplication     :  Name is: Mark