Spring Boot External Configuration

Explains how to use externalized configuration.

Properties Files

Using a Properties File

Basic Usage

Folder structure

|-build.gradle
`-src/main/
  |-java/sample/springboot/
  |  `-Main.java
  `-resources/
    `-application.properties

Main.java

package sample.springboot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    @Value("${sample.value}")
    private String value;

    public void hello() {
        System.out.println("sample.value = " + this.value);
    }
}

Execution result

sample.value = Hello Properties File!!
  • Place a properties file named application.properties under the classpath.
  • Spring Boot automatically reads the file.
  • Values in the properties file can be injected into Beans by using the @Value annotation.
  • Specify the value you want to retrieve in the ${property name} format.
Where to Put the File

There are several locations for properties files, and they are read in priority order.

  1. A file specified with --spring.config.location at startup.
  2. A file in the config directory directly under the current directory.
  3. A file directly under the current directory.
  4. A file in the config package directly under the classpath.
  5. A file directly under the classpath.

The lower the number, the higher the priority. Settings with lower priority are overwritten by higher-priority settings.

Folder structure inside the jar

|-application.properties
|-config/
|  `-application.properties
`-sample/springboot/
   `-Main.class

Folder structure at execution time

|-application.properties
|-other.properties
|-config/
| `-application.properties
`-build/libs/
  `-spring-boot-sample.jar

other.properties

value5=other

application.properties under the current directory’s config directory

value4=currentdir/config
value5=currentdir/config

application.properties under the current directory

value3=currentdir/
value4=currentdir/
value5=currentdir/

application.properties under the classpath config package

value2=classpath/config
value3=classpath/config
value4=classpath/config
value5=classpath/config

application.properties directly under the classpath

value1=classpath/
value2=classpath/
value3=classpath/
value4=classpath/
value5=classpath/

Main.java

package sample.springboot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    @Value("${value1}") private String value1;
    @Value("${value2}") private String value2;
    @Value("${value3}") private String value3;
    @Value("${value4}") private String value4;
    @Value("${value5}") private String value5;

    public void hello() {
        System.out.println("value1=" + value1);
        System.out.println("value2=" + value2);
        System.out.println("value3=" + value3);
        System.out.println("value4=" + value4);
        System.out.println("value5=" + value5);
    }
}

Run

$ java -jar build/libs/spring-boot-sample.jar --spring.config.location=other.properties

value1=classpath/
value2=classpath/config
value3=currentdir/
value4=currentdir/config
value5=other

The settings are overwritten according to the priority order.

Specify a Profile

Folder structure

|-application.properties
|-application-develop.properties
`-build/libs/
   `-spring-boot-sample.jar

application.properties

value=release module

application-develop.properties

value=develop module

Run

$ java -jar build/libs/spring-boot-sample.jar

value=release module

$ java -jar build/libs/spring-boot-sample.jar --spring.profiles.active=develop

value=develop module
  • Write a properties file in the application-{profile name}.properties format.
  • Specify the profile name to use with spring.profiles.active as a command-line argument.
    • In addition to command-line arguments, system properties and OS environment variables can also be used.
  • Then the properties file corresponding to the specified profile is loaded.

Mapping Properties with the Same Prefix to a Bean

Code

application.properties

person.firstName=Sato
person.last-name=Taro
person.age=18

Person.java

package sample.springboot;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

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

    private String firstName;
    private String lastName;
    private int age;

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void hello() {
        System.out.println(firstName + " " + lastName + " : " + age);
    }
}

Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
@EnableConfigurationProperties
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Person person = ctx.getBean(Person.class);
            person.hello();
        }
    }
}

Execution result

Sato Taro : 18
  • With @ConfigurationProperties, properties with a specific prefix can be mapped to a Bean.
    • The Bean needs setter methods.
    • Field names are mapped not only in camel case, but also with hyphen (-) and underscore (_) separators.
  • To enable this mechanism, add the @EnableConfigurationProperties annotation.
    • Strictly speaking, add it to a class annotated with @Configuration.

Using YAML

If the configuration file is application.yaml, YAML can be used.

Basic Mapping

application.yaml

aaa:
    bbb:
        ccc: Hoge
        ddd: Fuga
    eee:
        fff: Piyo

Main.java

package sample.springboot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    @Value("${aaa.bbb.ccc}") private String ccc;
    @Value("${aaa.bbb.ddd}") private String ddd;
    @Value("${aaa.eee.fff}") private String fff;

    public void hello() {
        System.out.println("ccc=" + ccc);
        System.out.println("ddd=" + ddd);
        System.out.println("fff=" + fff);
    }
}

Execution result

ccc=Hoge
ddd=Fuga
fff=Piyo

List Mapping

application.yaml

myconf:
    list:
        - hoge
        - fuga
        - piyo

MyConf.java

package sample.springboot;

import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="myconf")
public class MyConfig {

    private List<String> list;

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }
}

Main.java

package sample.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
@EnableConfigurationProperties
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            MyConfig conf = ctx.getBean(MyConfig.class);
            System.out.println(conf.getList());
        }
    }
}

Execution result

[hoge, fuga, piyo]
  • When Bean mapping is used, lists can also be mapped.

Passing Configuration Values Other Than Properties Files

Main.java

package sample.springboot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        try (ConfigurableApplicationContext ctx = SpringApplication.run(Main.class, args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    @Value("${value}") private String value;

    public void hello() {
        System.out.println("value=" + value);
    }
}

Command-Line Arguments

$ java -jar build/libs/spring-boot-sample.jar --value=commandline

value=commandline
  • Pass configuration values from command-line arguments with --[property name]=[value].

Java System Properties

$ java -Dvalue=systemproperty -jar build/libs/spring-boot-sample.jar

value=systemproperty
  • Pass configuration values from system properties with --D [property name]=[value].

OS Environment Variables

$ set value=osenvironment

$ java -jar build/libs/spring-boot-sample.jar

value=osenvironment

This example uses Windows.

Default Properties

Main.java

package sample.springboot;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        Map<String, Object> properties = new HashMap<>();
        properties.put("value", "default property");

        SpringApplication app = new SpringApplication(Main.class);
        app.setDefaultProperties(properties);

        try (ConfigurableApplicationContext ctx = app.run(args)) {
            Main m = ctx.getBean(Main.class);
            m.hello();
        }
    }

    @Value("${value}") private String value;

    public void hello() {
        System.out.println("value=" + value);
    }
}

Execution result

value=default property

Default settings can be specified with SpringApplication#setDefaultProperties(Map<String, Object>).

Property Priority

As with properties files, there is a priority order among the ways to pass configuration values, and higher-priority methods overwrite values specified by lower-priority methods.

The priority order is as follows.

  1. Command-line arguments
  2. Properties obtained from JNDI java:comp/env
  3. System properties
  4. OS environment variables
  5. Profile-specific properties files outside the jar
  6. Profile-specific properties files inside the jar
  7. Properties files outside the jar
  8. Properties files inside the jar
  9. Properties files specified with @PropertySource
  10. Default properties

Lower numbers have higher priority.