Spring Boot 外部設定値の優先順位

## 概要

- Spring Boot 2.2.0.M4 の Externalized Configuration (外部設定) の設定値の優先順位についてのドキュメントを日本語に翻訳した
- 原文: [Spring Boot Reference Documentation - 4.2. Externalized Configuration](https://docs.spring.io/spring-boot/docs/2.2.0.M4/reference/html/#boot-features-external-config)

## 日本語訳

外部設定

Spring Boot は、異なる環境で同じアプリケーションコードを動かせるように、設定を外部化することができます。
プロパティファイル、YAMLファイル、環境変数、コマンドライン引数を使って設定を外部化することができます。
設定値は @Value アノテーションを使用して Bean に直接インジェクションすることも、Spring の Environment を通じてアクセスすることも、@ConfigurationProperties を通じて構造化オブジェクトにバインドすることもできます。

Spring Boot は PropertySource という特別な順序付けの仕組みを使います。これは設定値を柔軟に上書きできるよう設計されています。

設定値は以下の優先順で適用されます:

1. ホームディレクトリの Devtools グローバル設定プロパティ（devtoolsがアクティブな場合は〜/.spring-boot-devtools.properties)。
2. テストの @TestPropertySource アノテーション。
3. テストのプロパティ属性。これは @SpringBootTest と、アプリケーションの特定の部分をテストするためのテストアノテーションで利用できる。
4. コマンドライン引数。
5. SPRING_APPLICATION_JSON に設定したプロパティ (環境変数やシステム・プロパティに埋め込まれたインラインJSON)。
6. ServletConfig 初期化パラメータ。
7. ServletContext 初期化パラメータ。
8. java:comp/env 由来の JNDI 属性。
9. Java のシステム・プロパティ (System.getProperties())。
10. OS の環境変数
11. random.* のプロパティのみを持っている RandomValuePropertySource。
12. 特定のプロファイル用で、JAR にパッケージングされていないアプリケーション・プロパティ (application-{profile}.properties と YAML)。
13. 特定のプロファイル用で、JAR にパッケージングされているアプリケーション・プロパティ (application-{profile}.properties と YAML)。
14. JAR にパッケージングされていないアプリケーション・プロパティ (application.properties と YAML)。
15. JAR にパッケージングされているアプリケーション・プロパティ (application.properties と YAML)。
16. @Configuration クラスの @PropertySource アノテーション。
17. デフォルト・プロパティ (SpringApplication.setDefaultProperties で指定された設定)。

## 原文 (英語)

4.2. Externalized Configuration

Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration. Property values can be injected directly into your beans by using the @Value annotation, accessed through Spring’s Environment abstraction, or be bound to structured objects through @ConfigurationProperties.

Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:

1. Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
2. @TestPropertySource annotations on your tests.
3. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.
4. Command line arguments.
5. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
6. ServletConfig init parameters.
7. ServletContext init parameters.
8. JNDI attributes from java:comp/env.
9. Java System properties (System.getProperties()).
10. OS environment variables.
11. A RandomValuePropertySource that has properties only in random.*.
12. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
13. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
14. Application properties outside of your packaged jar (application.properties and YAML variants).
15. Application properties packaged inside your jar (application.properties and YAML variants).
16. @PropertySource annotations on your @Configuration classes.
17. Default properties (specified by setting SpringApplication.setDefaultProperties).

## 優先順についての動作確認

サンプルコードを実行して、優先順を確認する。

### application.properties

application.properties に設定値を記述する。

```
message=Hello, application.properties!
```

### Application.java

```
package sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

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

### Controller.java

設定値 message を JSON で返すようにする。

```java
package sample;

import java.util.HashMap;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

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

  @RequestMapping("/")
  public HashMap<String, Object> index() {
    return new HashMap<String, Object>() {
      {
        put("message", message);
      }
    };
  }
}
```

### application.properties が適用される例

java コマンドで Spring Boot サーバを実行する。

```
$ java -jar target/sample.jar
```

サーバにアクセスすると application.properties に記述した message 設定値が返される。

```
$ curl http://localhost:8080/
{"message":"Hello, application.properties!"}
```

### Java のシステム・プロパティが適用される例

-D で spring.application.json という Java のシステムプロパティに JSON を指定し、java コマンドで Spring Boot サーバを実行する。

```
$ java -Dspring.application.json='{"message":"Hello, Java System properties!"}' -jar target/sample.jar
```

サーバにアクセスすると、Java のシステム・プロパティに指定した message 設定値が返される。

```
$ curl http://localhost:8080/
{"message":"Hello, Java System properties!"}
```

application.properties ではなく、Java のシステム・プロパティが優先されている。
これは、先のリストの9番と15番の優先順位で、9番のほうが優先順位が高いため。
「9. Java のシステム・プロパティ (System.getProperties())。」
「15. JAR にパッケージングされているアプリケーション・プロパティ (application-{profile}.properties と YAML)。」