環境別の設定切り替え

Spring Boot を使用すると、異なる環境で同じアプリケーションコードを操作できるように、設定を外部化したり、切り替えたりすることができます。Java プロパティファイル、YAML ファイル、環境変数、コマンドライン引数など、さまざまな外部設定ソースを使用できます。

プロパティ値は、@Value アノテーションを使用して直接 Bean に注入したり、Spring の Environment 抽象化を通じてアクセスしたり、@ConfigurationProperties を通じて構造化オブジェクトにバインドしたりできます。

Spring Boot は、値を適切にオーバーライドできるように設計された、非常に特殊な PropertySource 順序を使用します。後のプロパティソースは、以前のもので定義された値をオーバーライドできます。ソースは次の順序で考慮されます。

  1. デフォルトのプロパティ(SpringApplication.setDefaultProperties の設定により指定されます)。

  2. @Configuration クラスの @PropertySource (Javadoc) アノテーション。このようなプロパティソースは、アプリケーションコンテキストがリフレッシュされるまで Environment に追加されないことに注意してください。これは、リフレッシュが始まる前に読み込まれる logging.* や spring.main.* などの特定のプロパティを設定するには遅すぎます。

  3. 構成データ(application.properties ファイルなど)。

  4. random.* のみにプロパティを持つ RandomValuePropertySource

  5. OS 環境変数。

  6. Java システムプロパティ(System.getProperties())。

  7. java:comp/env からの JNDI 属性。

  8. ServletContext 初期化パラメーター。

  9. ServletConfig 初期化パラメーター。

  10. SPRING_APPLICATION_JSON のプロパティ(環境変数またはシステムプロパティに埋め込まれたインライン JSON)。

  11. コマンドライン引数。

  12. テストの properties 属性。@SpringBootTest (Javadoc) と、アプリケーションの特定のスライスをテストするためのテストアノテーションで使用できます。

  13. テスト内の @DynamicPropertySource (Javadoc) アノテーション。

  14. テストに関する @TestPropertySource (Javadoc) アノテーション。

  15. devtools がアクティブな場合、$HOME/.config/spring-boot ディレクトリの Devtools グローバル設定プロパティ

構成データファイルは、次の順序で考慮されます。

  1. jar(application.properties および YAML バリアント)内にパッケージ化されたアプリケーションプロパティ

  2. jar(application-{profile}.properties および YAML バリアント)内にパッケージ化されたプロファイル固有のアプリケーションプロパティ

  3. パッケージ化された jar 以外のアプリケーションプロパティapplication.properties および YAML バリアント)。

  4. パッケージ化された jar 以外のプロファイル固有のアプリケーションプロパティapplication-{profile}.properties および YAML バリアント)。

アプリケーション全体で 1 つの形式を使用することをお勧めします。.properties 形式と YAML 形式の両方の構成ファイルが同じ場所にある場合は、.properties が優先されます。
システムプロパティではなく環境変数を使用する場合、ほとんどのオペレーティングシステムはピリオドで区切られたキー名を許可しませんが、代わりにアンダースコアを使用できます(たとえば、spring.config.name の代わりに SPRING_CONFIG_NAME)。詳細については、環境変数からのバインディングを参照してください。
アプリケーションがサーブレットコンテナーまたはアプリケーションサーバーで実行されている場合は、環境変数やシステムプロパティの代わりに、または環境変数やシステムプロパティの代わりに、JNDI プロパティ(java:comp/env 内)またはサーブレットコンテキスト初期化パラメーターを使用できます。

具体例を提供するために、次の例に示すように、name プロパティを使用する @Component を開発するとします。

  • Java

  • Kotlin

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

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

	// ...

}
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component

@Component
class MyBean {

	@Value("\${name}")
	private val name: String? = null

	// ...

}

アプリケーションのクラスパス(たとえば、jar 内)に、name の適切なデフォルトのプロパティ値を提供する application.properties ファイルを含めることができます。新しい環境で実行する場合、name をオーバーライドする jar の外部で application.properties ファイルを提供できます。1 回限りのテストでは、特定のコマンドラインスイッチ(たとえば java -jar app.jar --name="Spring")で起動できます。

env および configprops エンドポイントは、プロパティに特定の値がある理由を判別できます。これらの 2 つのエンドポイントを使用して、予期しないプロパティ値を診断できます。詳細については、"本番対応機能" セクションを参照してください。

コマンドラインプロパティへのアクセス

デフォルトでは、SpringApplication はコマンドラインオプション引数(つまり、--server.port=9000 などの -- で始まる引数)を property に変換し、Spring Environment に追加します。前述のように、コマンドラインプロパティは常にファイルベースのプロパティソースよりも優先されます。

コマンドラインプロパティを Environment に追加したくない場合は、SpringApplication.setAddCommandLineProperties(false) を使用して無効にすることができます。

JSON アプリケーションのプロパティ

多くの場合、環境変数とシステムプロパティには制限があり、一部のプロパティ名は使用できません。これを支援するために、Spring Boot ではプロパティのブロックを単一の JSON 構造にエンコードできます。

アプリケーションが起動すると、spring.application.json または SPRING_APPLICATION_JSON プロパティが解析され、Environment に追加されます。

例: SPRING_APPLICATION_JSON プロパティは、環境変数として UN*X シェルのコマンドラインで指定できます。

$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar

上記の例では、Spring Environment の my.name=test になります。

同じ JSON をシステムプロパティとして提供することもできます。

$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar

または、コマンドライン引数を使用して JSON を提供することもできます。

$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'

従来のアプリケーションサーバーにデプロイする場合は、java:comp/env/spring.application.json という名前の JNDI 変数を使用することもできます。

JSON からの null 値が結果のプロパティソースに追加されますが、PropertySourcesPropertyResolver は null プロパティを欠損値として扱います。これは、JSON が null 値を持つ低次のプロパティソースからのプロパティをオーバーライドできないことを意味します。

外部アプリケーションプロパティ

Spring Boot は、アプリケーションの起動時に、次の場所から application.properties ファイルと application.yaml ファイルを自動的に検索してロードします。

  1. クラスパスから

    1. クラスパスのルート

    2. クラスパス /config パッケージ

  2. カレントディレクトリから

    1. 現在のディレクトリ

    2. 現在のディレクトリの config/ サブディレクトリ

    3. config/ サブディレクトリの直接の子ディレクトリ

リストは優先順位で並べられます(下位の項目の値が上位の項目の値を上書きします)。ロードされたファイルのドキュメントは、PropertySources として Spring Environment に追加されます。

構成ファイル名として application が気に入らない場合は、spring.config.name 環境プロパティを指定して別のファイル名に切り替えることができます。例: myproject.properties および myproject.yaml ファイルを検索するには、次のようにアプリケーションを実行できます。

$ java -jar myproject.jar --spring.config.name=myproject

spring.config.location 環境プロパティを使用して、明示的な場所を参照することもできます。このプロパティは、チェックする 1 つ以上の場所のコンマ区切りリストを受け入れます。

次の例は、2 つの異なるファイルを指定する方法を示しています。

$ java -jar myproject.jar --spring.config.location=\
	optional:classpath:/default.properties,\
	optional:classpath:/override.properties
場所がオプションであり、存在しなくてもかまわない場合は、プレフィックス optional: を使用します。
spring.config.namespring.config.locationspring.config.additional-location は、ロードする必要のあるファイルを決定するために非常に早い段階で使用されます。これらは、環境プロパティ(通常、OS 環境変数、システムプロパティ、コマンドライン引数)として定義する必要があります。

spring.config.location に(ファイルではなく)ディレクトリが含まれている場合、/ で終わる必要があります。実行時に、ロードされる前に spring.config.name から生成された名前が追加されます。spring.config.location で指定されたファイルは直接インポートされます。

ディレクトリとファイルの場所の両方の値も展開され、プロファイル固有のファイルをチェックします。例: classpath:myconfig.properties の spring.config.location がある場合は、適切な classpath:myconfig-<profile>.properties ファイルもロードされていることがわかります。

ほとんどの場合、追加する各 spring.config.location アイテムは単一のファイルまたはディレクトリを参照します。場所は定義された順序で処理され、後のものは前のものの値を上書きできます。

複雑な場所の設定があり、プロファイル固有の構成ファイルを使用している場合は、Spring Boot がグループ化する方法を認識できるように、さらにヒントを提供する必要がある場合があります。ロケーショングループは、すべて同じレベルと見なされるロケーションのコレクションです。例: すべてのクラスパスの場所をグループ化し、次にすべての外部の場所をグループ化することができます。地域グループ内のアイテムは ; で区切る必要があります。詳細については、"プロファイル固有のファイル" セクションの例を参照してください。

spring.config.location を使用して構成された場所は、デフォルトの場所を置き換えます。例: spring.config.location が値 optional:classpath:/custom-config/,optional:file:./custom-config/ で構成されている場合、考慮される場所の完全なセットは次のとおりです。

  1. optional:classpath:custom-config/

  2. optional:file:./custom-config/

場所を置き換えるのではなく、場所を追加したい場合は、spring.config.additional-location を使用できます。追加の場所からロードされたプロパティは、デフォルトの場所のプロパティを上書きできます。例: spring.config.additional-location が値 optional:classpath:/custom-config/,optional:file:./custom-config/ で構成されている場合、考慮される場所の完全なセットは次のとおりです。

  1. optional:classpath:/;optional:classpath:/config/

  2. optional:file:./;optional:file:./config/;optional:file:./config/*/

  3. optional:classpath:custom-config/

  4. optional:file:./custom-config/

この検索順序により、ある構成ファイルでデフォルト値を指定し、別の構成ファイルでそれらの値を選択的にオーバーライドできます。デフォルトの場所の 1 つで、application.properties (または spring.config.name で選択した他のベース名)でアプリケーションのデフォルト値を提供できます。これらのデフォルト値は、カスタムロケーションのいずれかにある別のファイルで実行時にオーバーライドできます。

オプションの場所

デフォルトでは、指定された構成データの場所が存在しない場合、Spring Boot は ConfigDataLocationNotFoundException をスローし、アプリケーションは起動しません。

場所を指定したいが、常に存在していなくてもかまわない場合は、optional: プレフィックスを使用できます。このプレフィックスは、spring.config.location プロパティと spring.config.additional-location プロパティ、および spring.config.import 宣言で使用できます。

例: optional:file:./myconfig.properties の spring.config.import 値を使用すると、myconfig.properties ファイルが欠落している場合でもアプリケーションを起動できます。

すべての ConfigDataLocationNotFoundExceptions を無視して、常にアプリケーションを起動し続ける場合は、spring.config.on-not-found プロパティを使用できます。SpringApplication.setDefaultProperties(…​) を使用するか、システム / 環境変数を使用して、値を ignore に設定します。

ワイルドカードの場所

構成ファイルの場所に最後のパスセグメントの * 文字が含まれている場合、ワイルドカードの場所と見なされます。構成がロードされるとワイルドカードが展開されるため、即時サブディレクトリもチェックされます。ワイルドカードの場所は、構成プロパティのソースが複数ある場合の Kubernetes などの環境で特に役立ちます。

例: Redis 構成と MySQL 構成がある場合は、これら 2 つの構成を別々に保持し、両方が application.properties ファイルに存在する必要がある場合があります。これにより、/config/redis/application.properties や /config/mysql/application.properties などの異なる場所に 2 つの別々の application.properties ファイルがマウントされる可能性があります。このような場合、ワイルドカードの場所が config/*/ の場合、両方のファイルが処理されます。

デフォルトでは、Spring Boot はデフォルトの検索場所に config/*/ を含みます。これは、jar の外部にある /config ディレクトリのすべてのサブディレクトリが検索されることを意味します。

spring.config.location および spring.config.additional-location プロパティを使用して、ワイルドカードの場所を自分で使用できます。

ワイルドカードの場所には、* が 1 つだけ含まれ、ディレクトリである検索場所の場合は */ で終わり、ファイルである検索場所の場合は */<filename> で終わる必要があります。ワイルドカードを使用した場所は、ファイル名の絶対パスに基づいてアルファベット順にソートされます。
ワイルドカードの場所は、外部ディレクトリでのみ機能します。classpath: の場所ではワイルドカードを使用できません。

プロファイル固有のファイル

application プロパティファイルだけでなく、Spring Boot は、命名規則 application-{profile} を使用してプロファイル固有のファイルをロードしようとします。例: アプリケーションが prod という名前のプロファイルをアクティブ化し、YAML ファイルを使用する場合、application.yaml と application-prod.yaml の両方が考慮されます。

プロファイル固有のプロパティは、標準の application.properties と同じ場所から読み込まれ、プロファイル固有のファイルは常に非特定のファイルを上書きします。複数のプロファイルが指定されている場合は、ラストウィン戦略が適用されます。例: プロファイル prod,live が spring.profiles.active プロパティで指定されている場合、application-prod.properties の値は application-live.properties の値で上書きできます。

ラストウィン戦略は、ロケーショングループレベルで適用されます。classpath:/cfg/,classpath:/ext/ の spring.config.location には、classpath:/cfg/;classpath:/ext/ と同じオーバーライドルールはありません。

例: 上記の prod,live の例を続けると、次のファイルがある可能性があります。

/cfg
  application-live.properties
/ext
  application-live.properties
  application-prod.properties

classpath:/cfg/,classpath:/ext/ の spring.config.location がある場合、すべての /ext ファイルの前にすべての /cfg ファイルを処理します。

  1. /cfg/application-live.properties

  2. /ext/application-prod.properties

  3. /ext/application-live.properties

代わりに classpath:/cfg/;classpath:/ext/ がある場合 (; 区切り文字を使用)、/cfg と /ext を同じレベルで処理します。

  1. /ext/application-prod.properties

  2. /cfg/application-live.properties

  3. /ext/application-live.properties

Environment には、アクティブなプロファイルが設定されていない場合に使用される一連のデフォルトプロファイル(デフォルトでは [default])があります。つまり、プロファイルが明示的にアクティブ化されていない場合、application-default のプロパティが考慮されます。

プロパティファイルは一度だけロードされます。プロファイル固有のプロパティファイルをすでに直接インポートしている場合は、2 回目にインポートされることはありません。

追加データのインポート

アプリケーションプロパティは、spring.config.import プロパティを使用して、他の場所からさらに構成データをインポートできます。インポートは、検出されたときに処理され、インポートを宣言するドキュメントのすぐ下に挿入された追加のドキュメントとして扱われます。

例: クラスパス application.properties ファイルに次のものがある場合があります。

  • プロパティ

  • YAML

spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
spring:
  application:
    name: "myapp"
  config:
    import: "optional:file:./dev.properties"

これにより、現在のディレクトリに dev.properties ファイルがインポートされます(そのようなファイルが存在する場合)。インポートされた dev.properties からの値は、インポートをトリガーしたファイルよりも優先されます。上記の例では、dev.properties は spring.application.name を別の値に再定義できます。

インポートは、宣言された回数に関係なく、一度だけインポートされます。インポートが properties/yaml ファイル内の単一のドキュメント内で定義される順序は重要ではありません。たとえば、以下の 2 つの例では同じ結果が得られます。

  • プロパティ

  • YAML

spring.config.import=my.properties
my.property=value
spring:
  config:
    import: "my.properties"
my:
  property: "value"
  • プロパティ

  • YAML

my.property=value
spring.config.import=my.properties
my:
  property: "value"
spring:
  config:
    import: "my.properties"

上記の両方の例で、my.properties ファイルの値は、インポートをトリガーしたファイルよりも優先されます。

1 つの spring.config.import キーで複数の場所を指定できます。場所は、定義された順序で処理され、後のインポートが優先されます。

必要に応じて、プロファイル固有のバリアントもインポートの対象と見なされます。上記の例では、my.properties と my-<profile>.properties バリアントの両方をインポートします。

Spring Boot には、さまざまな異なるロケーションアドレスをサポートできるプラグ可能な API が含まれています。デフォルトでは、Java プロパティ、YAML、「構成ツリー」をインポートできます。

サードパーティの jar は、追加のテクノロジのサポートを提供できます (ファイルがローカルである必要はありません)。例: 構成データが Consul、Apache ZooKeeper、Netflix Archaius などの外部ストアから取得されることが考えられます。

独自の場所をサポートする場合は、org.springframework.boot.context.config パッケージの ConfigDataLocationResolver クラスと ConfigDataLoader クラスを参照してください。

拡張機能のないファイルのインポート

一部のクラウドプラットフォームは、ボリュームにマウントされたファイルにファイル拡張子を追加できません。これらの拡張子のないファイルをインポートするには、Spring Boot にヒントを与えて、ロードする方法を認識させる必要があります。これを行うには、角括弧に拡張ヒントを配置します。

例: yaml としてインポートしたい /etc/config/myconfig ファイルがあるとします。以下を使用して、application.properties からインポートできます。

  • プロパティ

  • YAML

spring.config.import=file:/etc/config/myconfig[.yaml]
spring:
  config:
    import: "file:/etc/config/myconfig[.yaml]"

構成ツリーの使用

クラウドプラットフォーム(Kubernetes など)でアプリケーションを実行する場合、プラットフォームが提供する構成値を読み取る必要があることがよくあります。このような目的で環境変数を使用することは珍しくありませんが、特に値をシークレットにしておくことになっている場合、これには欠点があります。

環境変数の代わりに、多くのクラウドプラットフォームで、構成をマウントされたデータボリュームにマッピングできるようになりました。例: Kubernetes は ConfigMaps (英語) Secrets (英語) の両方をボリュームマウントできます。

使用できる一般的なボリュームマウントパターンは 2 つあります。

  1. 1 つのファイルには、プロパティの完全なセットが含まれています(通常は YAML として記述されます)。

  2. 複数のファイルがディレクトリツリーに書き込まれ、ファイル名が「キー」になり、内容が「値」になります。

最初のケースでは、上記のように spring.config.import を使用して YAML またはプロパティファイルを直接インポートできます。2 番目のケースでは、configtree: プレフィックスを使用して、すべてのファイルをプロパティとして公開する必要があることを Spring Boot が認識できるようにする必要があります。

例として、Kubernetes が次のボリュームをマウントしたと想像してみましょう。

etc/
  config/
    myapp/
      username
      password

username ファイルの内容は構成値になり、password の内容はシークレットになります。

これらのプロパティをインポートするには、application.properties または application.yaml ファイルに以下を追加します。

  • プロパティ

  • YAML

spring.config.import=optional:configtree:/etc/config/
spring:
  config:
    import: "optional:configtree:/etc/config/"

その後、通常の方法で Environment から myapp.username および myapp.password プロパティにアクセスまたは挿入できます。

構成ツリーのフォルダーとファイルの名前がプロパティ名を形成します。上の例では、username および password としてプロパティにアクセスするには、spring.config.import を optional:configtree:/etc/config/myapp に設定します。
ドット表記のファイル名も正しくマッピングされます。例: 上記の例では、/etc/config の myapp.username という名前のファイルは、Environment の myapp.username プロパティになります。
構成ツリーの値は、予想される内容に応じて、文字列 String 型と byte[] 型の両方にバインドできます。

同じ親フォルダーからインポートする複数の構成ツリーがある場合は、ワイルドカードショートカットを使用できます。/*/ で終わる configtree: の場所は、すべての直接の子を構成ツリーとしてインポートします。非ワイルドカードインポートと同様に、各構成ツリーのフォルダーとファイルの名前がプロパティ名を形成します。

例: 次のボリュームがある場合:

etc/
  config/
    dbconfig/
      db/
        username
        password
    mqconfig/
      mq/
        username
        password

インポート場所として configtree:/etc/config/*/ を使用できます。

  • プロパティ

  • YAML

spring.config.import=optional:configtree:/etc/config/*/
spring:
  config:
    import: "optional:configtree:/etc/config/*/"

これにより、db.usernamedb.passwordmq.usernamemq.password プロパティが追加されます。

ワイルドカードを使用してロードされたディレクトリは、アルファベット順にソートされます。別のオーダーが必要な場合は、各場所を個別のインポートとしてリストする必要があります

構成ツリーは、Docker シークレットにも使用できます。Docker スウォームサービスにシークレットへのアクセスが許可されると、シークレットはコンテナーにマウントされます。例: db.password という名前のシークレットが /run/secrets/ の場所にマウントされている場合、以下を使用して db.password を Spring 環境で使用可能にすることができます。

  • プロパティ

  • YAML

spring.config.import=optional:configtree:/run/secrets/
spring:
  config:
    import: "optional:configtree:/run/secrets/"

プロパティプレースホルダー

application.properties および application.yaml の値は、使用時に既存の Environment でフィルタリングされるため、以前に定義された値(たとえば、システムプロパティまたは環境変数から)を参照することができます。標準の ${name} プロパティ - プレースホルダー構文は、値内のどこでも使用できます。プロパティプレースホルダーは、: を使用してデフォルト値を指定し、デフォルト値をプロパティ名から分離することもできます(例: ${name:default})。

次の例では、デフォルトがある場合とない場合のプレースホルダーの使用を示しています。

  • プロパティ

  • YAML

app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
app:
  name: "MyApp"
  description: "${app.name} is a Spring Boot application written by ${username:Unknown}"

username プロパティが他の場所に設定されていないと仮定すると、app.description の値は MyApp is a Spring Boot application written by Unknown になります。

プレースホルダー内のプロパティ名は、常に正規形(小文字のみを使用する kebab-case)を使用して参照する必要があります。これにより、Spring Boot は、@ConfigurationPropertiesバインドを緩和した場合と同じロジックを使用できるようになります。

例: ${demo.item-price} は、application.properties ファイルから demo.item-price および demo.itemPrice フォームを取得し、システム環境から DEMO_ITEMPRICE を取得します。代わりに ${demo.itemPrice} を使用した場合、demo.item-price および DEMO_ITEMPRICE は考慮されません。

この手法を使用して、既存の Spring Boot プロパティの「短い」バリアントを作成することもできます。詳細については、「短い」コマンドライン引数を使用する使い方を参照してください。

マルチドキュメントファイルの操作

Spring Boot を使用すると、単一の物理ファイルを複数の論理ドキュメントに分割し、それぞれを個別に追加できます。ドキュメントは上から下に順番に処理されます。後のドキュメントは、前のドキュメントで定義されたプロパティを上書きできます。

application.yaml ファイルの場合、標準の YAML マルチドキュメント構文が使用されます。3 つの連続するハイフンは、1 つのドキュメントの終わりと、次のドキュメントの始まりを表します。

例: 次のファイルには 2 つの論理ドキュメントがあります。

spring:
  application:
    name: "MyApp"
---
spring:
  application:
    name: "MyCloudApp"
  config:
    activate:
      on-cloud-platform: "kubernetes"

application.properties ファイルの場合、特別な #--- または !--- コメントを使用してドキュメントの分割をマークします。

spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
プロパティファイルの区切り記号には、先頭に空白を入れてはならず、正確に 3 つのハイフン文字を含める必要があります。セパレータの直前と直後の行は、同じコメントプレフィックスであってはなりません。
マルチドキュメントプロパティファイルは、spring.config.activate.on-profile などのアクティベーションプロパティと組み合わせて使用されることがよくあります。詳細については、次のセクションを参照してください。
マルチドキュメントプロパティファイルは、@PropertySource または @TestPropertySource アノテーションを使用してロードすることはできません。

アクティベーションプロパティ

特定の条件が満たされた場合にのみ、特定のプロパティのセットをアクティブ化すると便利な場合があります。例: 特定のプロファイルがアクティブな場合にのみ関連するプロパティがある場合があります。

spring.config.activate.* を使用して、プロパティドキュメントを条件付きでアクティブ化できます。

次のアクティベーションプロパティを使用できます。

表 1: アクティベーションプロパティ
プロパティ メモ

on-profile

ドキュメントをアクティブにするために一致する必要があるプロファイル式。

on-cloud-platform

ドキュメントをアクティブにするために検出する必要がある CloudPlatform

例: 以下は、2 番目のドキュメントが Kubernetes で実行されている場合、および "prod" プロファイルまたは "staging" プロファイルのいずれかがアクティブである場合にのみアクティブになることを指定します。

  • プロパティ

  • YAML

myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
myprop:
  "always-set"
---
spring:
  config:
    activate:
      on-cloud-platform: "kubernetes"
      on-profile: "prod | staging"
myotherprop: "sometimes-set"

暗号化プロパティ

Spring Boot は、プロパティ値を暗号化するための組み込みサポートを提供しませんが、Spring Environment に含まれる値を変更するために必要なフックポイントを提供します。EnvironmentPostProcessor インターフェースを使用すると、アプリケーションの開始前に Environment を操作できます。詳細については、開始する前に環境または ApplicationContext をカスタマイズするを参照してください。

クレデンシャルとパスワードを安全に保存する方法が必要な場合、Spring Cloud Vault (英語) プロジェクトは、外部化された設定を HashiCorp Vault (英語) に保存するためのサポートを提供します。

YAML の操作

YAML (英語) は JSON のスーパーセットであるため、階層構成データを指定するための便利な形式です。SpringApplication クラスは、クラスパスに SnakeYAML [GitHub] (英語) ライブラリがある場合は常に、プロパティの代替として YAML を自動的にサポートします。

「スターター」を使用すると、spring-boot-starter によって SnakeYAML が自動的に提供されます。

YAML をプロパティにマッピングする

YAML ドキュメントは、階層形式から Spring Environment で使用できるフラットな構造に変換する必要があります。例: 次の YAML ドキュメントを検討してください:

environments:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"

Environment からこれらのプロパティにアクセスするために、これらは次のようにフラット化されます。

environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App

同様に、YAML リストもフラット化する必要があります。これらは、[index] デリファレンスを使用したプロパティキーとして表されます。例: 次の YAML を検討してください:

 my:
  servers:
  - "dev.example.com"
  - "another.example.com"

前述の例は、次のプロパティに変換されます。

my.servers[0]=dev.example.com
my.servers[1]=another.example.com
[index] 表記を使用するプロパティは、Spring Boot の Binder クラスを使用して Java List または Set オブジェクトにバインドできます。詳細については、以下の "型安全な構成プロパティ" セクションを参照してください。
YAML ファイルは、@PropertySource または @TestPropertySource アノテーションを使用してロードすることはできません。そのように値をロードする必要がある場合は、プロパティファイルを使用する必要があります。

YAML を直接読み込む

Spring Framework は、YAML ドキュメントのロードに使用できる 2 つの便利なクラスを提供します。YamlPropertiesFactoryBean は YAML を Properties としてロードし、YamlMapFactoryBean は YAML を Map としてロードします。

YAML を Spring PropertySource としてロードする場合は、YamlPropertySourceLoader クラスを使用することもできます。

ランダム値の構成

RandomValuePropertySource は、ランダムな値を挿入するのに便利です(たとえば、シークレットやテストケースに)。次の例に示すように、整数、long、uuid、文字列を生成できます。

  • プロパティ

  • YAML

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number-less-than-ten=${random.int(10)}
my.number-in-range=${random.int[1024,65536]}
my:
  secret: "${random.value}"
  number: "${random.int}"
  bignumber: "${random.long}"
  uuid: "${random.uuid}"
  number-less-than-ten: "${random.int(10)}"
  number-in-range: "${random.int[1024,65536]}"

random.int* 構文は OPEN value (,max) CLOSE です。OPEN,CLOSE は任意の文字で、value,max は整数です。max が指定されている場合、value が最小値で、max が最大値(排他的)です。

システム環境プロパティの構成

Spring Boot は、環境プロパティのプレフィックスの設定をサポートしています。これは、システム環境が異なる構成要件を持つ複数の Spring Boot アプリケーションによって共有されている場合に役立ちます。システム環境プロパティのプレフィックスは、SpringApplication で直接設定できます。

例: プレフィックスを input に設定すると、remote.timeout などのプロパティもシステム環境で input.remote.timeout として解決されます。

型安全な構成プロパティ

@Value("${property}") アノテーションを使用して構成プロパティを注入することは、特に複数のプロパティを使用している場合、またはデータが本質的に階層的である場合には、面倒な場合があります。Spring Boot は、強く型付けされた Bean がアプリケーションの構成を管理および検証できるようにするプロパティを操作する代替方法を提供します。

JavaBean プロパティのバインディング

次の例に示すように、標準 JavaBean プロパティを宣言する Bean をバインドすることができます。

  • Java

  • Kotlin

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

@ConfigurationProperties("my.service")
public class MyProperties {

	private boolean enabled;

	private InetAddress remoteAddress;

	private final Security security = new Security();

	// getters / setters...

	public boolean isEnabled() {
		return this.enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	public InetAddress getRemoteAddress() {
		return this.remoteAddress;
	}

	public void setRemoteAddress(InetAddress remoteAddress) {
		this.remoteAddress = remoteAddress;
	}

	public Security getSecurity() {
		return this.security;
	}

	public static class Security {

		private String username;

		private String password;

		private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

		// getters / setters...

		public String getUsername() {
			return this.username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

		public String getPassword() {
			return this.password;
		}

		public void setPassword(String password) {
			this.password = password;
		}

		public List<String> getRoles() {
			return this.roles;
		}

		public void setRoles(List<String> roles) {
			this.roles = roles;
		}

	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import java.net.InetAddress

@ConfigurationProperties("my.service")
class MyProperties {

	var isEnabled = false

	var remoteAddress: InetAddress? = null

	val security = Security()

	class Security {

		var username: String? = null

		var password: String? = null

		var roles: List<String> = ArrayList(setOf("USER"))

	}

}

前述の POJO は、次のプロパティを定義します。

  • my.service.enabled、デフォルトでは false の値。

  •  String から強制変換できる型の my.service.remote-address

  • my.service.security.username、ネストされた「セキュリティ」オブジェクト。その名前はプロパティの名前によって決定されます。特に、その型はまったく使用されておらず、SecurityProperties である可能性があります。

  • my.service.security.password.

  • my.service.security.roles。デフォルトは USER である String のコレクションです。

プロパティファイル、YAML ファイル、環境変数、その他のメカニズムを介して構成された Spring Boot で使用可能な @ConfigurationProperties クラスにマップされるプロパティは、パブリック API ですが、クラス自体のアクセサー(getter/setter)を直接使用するためのものではありません。

このような配置は、デフォルトの空のコンストラクターに依存しており、getter と setter は通常必須です。これは、バインディングが Spring MVC の場合と同様に、標準の Java Bean プロパティ記述子を介して行われるためです。setter は、次の場合に省略できます。

  • マップは、初期化されている限り、getter を必要としますが、必ずしも setter を必要とするわけではありません。バインダーによって変更できるためです。

  • コレクションと配列には、インデックス(通常は YAML を使用)または単一のコンマ区切り値(プロパティ)を使用してアクセスできます。後者の場合、setter は必須です。そのような型には、常に setter を追加することをお勧めします。コレクションを初期化する場合は、不変でないことを確認してください(前の例のように)。

  • ネストされた POJO プロパティが初期化される場合(前述の例の Security フィールドのように)、setter は必要ありません。デフォルトのコンストラクターを使用して、バインダーがその場でインスタンスを作成するようにするには、setter が必要です。

プロジェクト Lombok を使用して、getter と setter を自動的に追加する人もいます。Lombok はオブジェクトをインスタンス化するためにコンテナーによって自動的に使用されるため、そのような型の特定のコンストラクターを生成しないように注意してください。

最後に、標準の Java Bean プロパティのみが考慮され、静的プロパティのバインドはサポートされていません。

コンストラクターのバインド

前のセクションの例は、次の例に示すように不変の方法で書き換えることができます。

  • Java

  • Kotlin

import java.net.InetAddress;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;

@ConfigurationProperties("my.service")
public class MyProperties {

	// fields...

	private final boolean enabled;

	private final InetAddress remoteAddress;

	private final Security security;


	public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
		this.enabled = enabled;
		this.remoteAddress = remoteAddress;
		this.security = security;
	}

	// getters...

	public boolean isEnabled() {
		return this.enabled;
	}

	public InetAddress getRemoteAddress() {
		return this.remoteAddress;
	}

	public Security getSecurity() {
		return this.security;
	}

	public static class Security {

		// fields...

		private final String username;

		private final String password;

		private final List<String> roles;


		public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
			this.username = username;
			this.password = password;
			this.roles = roles;
		}

		// getters...

		public String getUsername() {
			return this.username;
		}

		public String getPassword() {
			return this.password;
		}

		public List<String> getRoles() {
			return this.roles;
		}

	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import java.net.InetAddress

@ConfigurationProperties("my.service")
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
		val security: Security) {

	class Security(val username: String, val password: String,
			@param:DefaultValue("USER") val roles: List<String>)

}

この設定では、単一のパラメーター化されたコンストラクターが存在するということは、コンストラクターバインディングを使用する必要があることを意味します。つまり、バインダーは、バインドするパラメーターを持つコンストラクターを見つけます。クラスに複数のコンストラクターがある場合は、@ConstructorBinding アノテーションを使用して、コンストラクターバインディングに使用するコンストラクターを指定できます。単一のパラメーター化されたコンストラクターを持つクラスのコンストラクターバインディングをオプトアウトするには、コンストラクターに @Autowired アノテーションを付ける、または private にする必要があります。コンストラクターバインディングはレコードで使用できます。レコードに複数のコンストラクターがない限り、@ConstructorBinding を使用する必要はありません。

コンストラクターにバインドされたクラス(上記の例の Security など)のネストされたメンバーも、コンストラクターを介してバインドされます。

デフォルト値は、コンストラクターパラメーターおよびレコードコンポーネントで @DefaultValue を使用して指定できます。変換サービスは、アノテーションの String 値を欠落しているプロパティのターゲット型に強制変換するために適用されます。

前の例を参照すると、プロパティが Security にバインドされていない場合、MyProperties インスタンスには security の null 値が含まれます。プロパティがバインドされていない場合でも Security の null 以外のインスタンスを含めるには (Kotlin を使用する場合、Security の username および password パラメーターはデフォルト値を持たないため、null 可能として宣言する必要があります)、空の @DefaultValue アノテーション:

  • Java

  • Kotlin

	public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
		this.enabled = enabled;
		this.remoteAddress = remoteAddress;
		this.security = security;
	}
class MyProperties(val enabled: Boolean, val remoteAddress: InetAddress,
		@DefaultValue val security: Security) {

	class Security(val username: String?, val password: String?,
			@param:DefaultValue("USER") val roles: List<String>)

}
コンストラクターバインディングを使用するには、@EnableConfigurationProperties または構成プロパティスキャンを使用してクラスを有効にする必要があります。通常の Spring メカニズムによって作成された Bean でコンストラクターバインディングを使用することはできません。(たとえば、@Component Bean、@Bean メソッドを使用して作成された Bean、または @Import を使用してロードされた Bean )
コンストラクターバインディングを使用するには、クラスを -parameters でコンパイルする必要があります。これは、Spring Boot の Gradle プラグインを使用する場合、または Maven と spring-boot-starter-parent を使用する場合に自動的に行われます。
java.util.Optional と @ConfigurationProperties の併用は、主に戻り値の型としての使用を目的としているためお勧めしません。そのため、構成プロパティの注入には適していません。他の型のプロパティとの一貫性を保つために、Optional プロパティを宣言し、それに値がない場合、空の Optional ではなく null がバインドされます。

@ConfigurationProperties アノテーション付き型の有効化

Spring Boot は、@ConfigurationProperties 型をバインドし、Bean として登録するためのインフラストラクチャを提供します。クラスごとに構成プロパティを有効にするか、コンポーネントスキャンと同様に機能する構成プロパティスキャンを有効にすることができます。

@ConfigurationProperties アノテーションが付けられたクラスは、たとえば、独自の自動構成を開発している場合や、条件付きで有効にしたい場合など、スキャンに適さない場合があります。これらの場合、@EnableConfigurationProperties アノテーションを使用して処理する型のリストを指定します。これは、次の例に示すように、@Configuration クラスで実行できます。

  • Java

  • Kotlin

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {

}
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties::class)
class MyConfiguration
  • Java

  • Kotlin

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

@ConfigurationProperties("some.properties")
public class SomeProperties {

}
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("some.properties")
class SomeProperties

構成プロパティのスキャンを使用するには、@ConfigurationPropertiesScan アノテーションをアプリケーションに追加します。通常、@SpringBootApplication アノテーションが付けられたメインアプリケーションクラスに追加されますが、任意の @Configuration クラスに追加できます。デフォルトでは、アノテーションを宣言するクラスのパッケージからスキャンが行われます。スキャンする特定のパッケージを定義する場合は、次の例に示すように定義できます。

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {

}
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.context.properties.ConfigurationPropertiesScan

@SpringBootApplication
@ConfigurationPropertiesScan("com.example.app", "com.example.another")
class MyApplication

@ConfigurationProperties Bean が構成プロパティスキャンを使用して、または @EnableConfigurationProperties を介して登録される場合、Bean は従来の名前 <prefix>-<fqn> を持ちます。ここで、<prefix> は @ConfigurationProperties アノテーションで指定された環境キー接頭部であり、<fqn> は Bean の完全修飾名です。アノテーションにプレフィックスが含まれていない場合は、Bean の完全修飾名のみが使用されます。

com.example.app パッケージにあると仮定すると、上記の SomeProperties の例の Bean 名は some.properties-com.example.app.SomeProperties です。

@ConfigurationProperties は環境のみを扱い、特にコンテキストから他の Bean を注入しないことをお勧めします。コーナーケースの場合、setter インジェクションを使用するか、フレームワークによって提供される *Aware インターフェースのいずれか(Environment へのアクセスが必要な場合は EnvironmentAware など)を使用できます。それでもコンストラクターを使用して他の Bean を注入する場合は、構成プロパティ Bean に @Component のアノテーションを付け、JavaBean ベースのプロパティバインディングを使用する必要があります。

@ConfigurationProperties アノテーション付き型の使用

このスタイルの構成は、次の例に示すように、SpringApplication 外部 YAML 構成で特にうまく機能します。

my:
  service:
    remote-address: 192.168.1.1
    security:
      username: "admin"
      roles:
      - "USER"
      - "ADMIN"

@ConfigurationProperties Bean を使用するには、次の例に示すように、他の Bean と同じ方法で注入できます。

  • Java

  • Kotlin

import org.springframework.stereotype.Service;

@Service
public class MyService {

	private final MyProperties properties;

	public MyService(MyProperties properties) {
		this.properties = properties;
	}

	public void openConnection() {
		Server server = new Server(this.properties.getRemoteAddress());
		server.start();
		// ...
	}

	// ...

}
import org.springframework.stereotype.Service

@Service
class MyService(val properties: MyProperties) {

	fun openConnection() {
		val server = Server(properties.remoteAddress)
		server.start()
		// ...
	}

	// ...

}
@ConfigurationProperties を使用すると、独自のキーの自動補完を提供するために IDE で使用できるメタデータファイルを生成することもできます。詳細については付録を参照してください。

サードパーティの構成

@ConfigurationProperties を使用してクラスにアノテーションを付けるだけでなく、パブリック @Bean メソッドでも使用できます。これは、コントロール外のサードパーティコンポーネントにプロパティをバインドする場合に特に役立ちます。

Environment プロパティから Bean を構成するには、次の例に示すように、@ConfigurationProperties を Bean 登録に追加します。

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {

	@Bean
	@ConfigurationProperties(prefix = "another")
	public AnotherComponent anotherComponent() {
		return new AnotherComponent();
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class ThirdPartyConfiguration {

	@Bean
	@ConfigurationProperties(prefix = "another")
	fun anotherComponent(): AnotherComponent = AnotherComponent()

}

another プレフィックスで定義された JavaBean プロパティは、前述の SomeProperties の例と同様の方法で、その AnotherComponent Bean にマッピングされます。

緩いバインディング

Spring Boot は、Environment プロパティを @ConfigurationProperties Bean にバインドするためにいくつかの緩和されたルールを使用しているため、Environment プロパティ名と Bean プロパティ名が完全に一致する必要はありません。これが役立つ一般的な例には、ダッシュで区切られた環境プロパティ(たとえば、context-path が contextPath にバインド)、大文字の環境プロパティ(たとえば、PORT が port にバインド)があります。

例として、次の @ConfigurationProperties クラスを検討してください。

  • Java

  • Kotlin

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

@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {

	private String firstName;

	public String getFirstName() {
		return this.firstName;
	}

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

}
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties(prefix = "my.main-project.person")
class MyPersonProperties {

	var firstName: String? = null

}

上記のコードでは、次のプロパティ名をすべて使用できます。

表 2: 緩いバインディング
プロパティ メモ

my.main-project.person.first-name

Kebab ケース。.properties および YAML ファイルでの使用が推奨されます。

my.main-project.person.firstName

標準のキャメルケースの構文。

my.main-project.person.first_name

アンダースコア表記。.properties および YAML ファイルで使用される代替形式です。

MY_MAINPROJECT_PERSON_FIRSTNAME

システム環境変数を使用する場合に推奨される大文字形式。

アノテーションの prefix 値はケバブの場合(小文字で、my.main-project.person などの - で区切られている)でなければなりません
表 3: プロパティソースごとの緩いバインディングルール
プロパティソース シンプル リスト

プロパティファイル

キャメルケース、ケバブケース、アンダースコア表記

[ ] またはコンマ区切り値を使用した標準リスト構文

YAML ファイル

キャメルケース、ケバブケース、アンダースコア表記

標準の YAML リスト構文またはコンマ区切り値

環境変数

区切り文字としてアンダースコアを使用した大文字の形式(環境変数からのバインディングを参照)。

アンダースコアで囲まれた数値 ( 環境変数からのバインディングを参照してください)

システムプロパティ

キャメルケース、ケバブケース、アンダースコア表記

[ ] またはコンマ区切り値を使用した標準リスト構文

可能な場合、プロパティは my.person.first-name=Rod などの小文字のケバブ形式で保存することをお勧めします。

マップのバインド

Map プロパティにバインドする場合、元の key 値が保持されるように、特別な括弧表記を使用する必要がある場合があります。キーが [] で囲まれていない場合、英数字、-. 以外の文字はすべて削除されます。

例: 次のプロパティを Map<String,String> にバインドすることを検討してください。

  • プロパティ

  • YAML

my.map[/key1]=value1
my.map[/key2]=value2
my.map./key3=value3
my:
  map:
    "[/key1]": "value1"
    "[/key2]": "value2"
    "/key3": "value3"
YAML ファイルの場合、キーを適切に解析するには、括弧を引用符で囲む必要があります。

上記のプロパティは、マップ内のキーとして /key1/key2key3 を使用して Map にバインドされます。スラッシュは角括弧で囲まれていなかったため、key3 から削除されました。

スカラー値にバインドする場合、. を含むキーを [] で囲む必要はありません。スカラー値には、Object を除く java.lang パッケージの列挙型とすべての型が含まれます。a.b=c を Map<String, String> にバインドすると、キーに . が保持され、エントリ {"a.b"="c"} のマップが返されます。その他の型では、key に . が含まれている場合は、括弧表記を使用する必要があります。例: a.b=c を Map<String, Object> にバインドすると、エントリ {"a"={"b"="c"}} のマップが返されますが、[a.b]=c はエントリ {"a.b"="c"} のマップが返されます。

環境変数からのバインディング

ほとんどのオペレーティングシステムでは、環境変数に使用できる名前に関する厳格なルールが適用されます。例: Linux シェル変数には、文字(a から z または A から Z)、数字(0 から 9)または下線文字(_)のみを含めることができます。慣例により、Unix シェル変数も大文字で名前が付けられます。

Spring Boot の緩いバインディングルールは、可能な限り、これらの命名制限と互換性を持つように設計されています。

正規形式のプロパティ名を環境変数名に変換するには、次のルールに従います。

  • ドット(.)をアンダースコア(_)に置き換えます。

  • ダッシュ(-)をすべて削除します。

  • 大文字に変換します。

例: 構成プロパティ spring.main.log-startup-info は SPRING_MAIN_LOGSTARTUPINFO という名前の環境変数になります。

環境変数は、オブジェクトリストにバインドするときにも使用できます。List にバインドするには、要素名を変数名でアンダースコアで囲む必要があります。

例: 構成プロパティ my.service[0].other は、MY_SERVICE_0_OTHER という名前の環境変数を使用します。

キャッシング

緩和バインディングでは、キャッシュを使用してパフォーマンスを向上させます。デフォルトでは、このキャッシュは不変プロパティソースにのみ適用されます。この動作をカスタマイズするには、たとえば変更可能なプロパティソースのキャッシュを有効にするには、ConfigurationPropertyCaching を使用します。

複合型のマージ

リストが複数の場所で構成されている場合、オーバーライドはリスト全体を置き換えることで機能します。

例: null である name および description 属性を持つ MyPojo オブジェクトをデフォルトと想定します。次の例は、MyProperties から MyPojo オブジェクトのリストを公開します。

  • Java

  • Kotlin

import java.util.ArrayList;
import java.util.List;

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

@ConfigurationProperties("my")
public class MyProperties {

	private final List<MyPojo> list = new ArrayList<>();

	public List<MyPojo> getList() {
		return this.list;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("my")
class MyProperties {

	val list: List<MyPojo> = ArrayList()

}

次の構成を検討してください。

  • プロパティ

  • YAML

my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
my:
  list:
  - name: "my name"
    description: "my description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

dev プロファイルがアクティブでない場合、MyProperties.list には、前に定義したように 1 つの MyPojo エントリが含まれます。ただし、dev プロファイルが有効になっている場合、list にはまだ 1 つのエントリしか含まれていません(名前が my another name で説明が null)。この構成で、2 番目の MyPojo インスタンスはリストに追加されず、アイテムはマージされません。

List が複数のプロファイルで指定されている場合、最高の優先順位を持つプロファイル(およびそのプロファイルのみ)が使用されます。次の例を考えてみましょう。

  • プロパティ

  • YAML

my.list[0].name=my name
my.list[0].description=my description
my.list[1].name=another name
my.list[1].description=another description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
my:
  list:
  - name: "my name"
    description: "my description"
  - name: "another name"
    description: "another description"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  list:
  - name: "my another name"

上記の例で、dev プロファイルがアクティブである場合、MyProperties.list には 1 つの  MyPojo エントリ(名前 my another name および説明 null)が含まれます。YAML の場合、コンマ区切りリストと YAML リストの両方を使用して、リストの内容を完全にオーバーライドできます。

Map プロパティの場合、複数のソースから取得したプロパティ値とバインドできます。ただし、複数のソースの同じプロパティの場合、優先度が最も高いプロパティが使用されます。次の例は、MyProperties から Map<String, MyPojo> を公開します。

  • Java

  • Kotlin

import java.util.LinkedHashMap;
import java.util.Map;

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

@ConfigurationProperties("my")
public class MyProperties {

	private final Map<String, MyPojo> map = new LinkedHashMap<>();

	public Map<String, MyPojo> getMap() {
		return this.map;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties

@ConfigurationProperties("my")
class MyProperties {

	val map: Map<String, MyPojo> = LinkedHashMap()

}

次の構成を検討してください。

  • プロパティ

  • YAML

my.map.key1.name=my name 1
my.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
my.map.key1.name=dev name 1
my.map.key2.name=dev name 2
my.map.key2.description=dev description 2
my:
  map:
    key1:
      name: "my name 1"
      description: "my description 1"
---
spring:
  config:
    activate:
      on-profile: "dev"
my:
  map:
    key1:
      name: "dev name 1"
    key2:
      name: "dev name 2"
      description: "dev description 2"

dev プロファイルがアクティブでない場合、MyProperties.map にはキー key1 (名前 my name 1 および説明 my description 1)を持つ 1 つのエントリが含まれます。ただし、dev プロファイルが有効になっている場合、map には、キー key1 (名前 dev name 1 および説明 my description 1)および key2 (名前 dev name 2 および説明 dev description 2)の 2 つのエントリが含まれます。

上記のマージルールは、ファイルだけでなく、すべてのプロパティソースからのプロパティに適用されます。

プロパティの変換

Spring Boot は、@ConfigurationProperties Bean にバインドするときに、外部アプリケーションプロパティを正しい型に強制しようとします。カスタム型の変換が必要な場合は、ConversionService Bean(conversionService という名前の Bean を使用)またはカスタムプロパティエディター(CustomEditorConfigurer Bean を使用)またはカスタム Converters (@ConfigurationPropertiesBinding としてアノテーション付けされた Bean 定義を使用)を提供できます。

この Bean はアプリケーションライフサイクルの非常に早い段階でリクエストされるため、ConversionService が使用している依存関係を必ず制限してください。通常、必要な依存関係は作成時に完全に初期化されない場合があります。構成キーの強制に不要なカスタム ConversionService の名前を変更し、@ConfigurationPropertiesBinding で修飾されたカスタムコンバーターのみに依存することができます。

時間ベースの期間変換

Spring Boot は、期間を表現するための専用サポートを備えています。java.time.Duration プロパティを公開する場合、アプリケーションプロパティで次の形式を使用できます。

  • 通常の long 表現 (@DurationUnit が指定されていない限り、デフォルトの単位としてミリ秒を使用する)

  • java.time.Duration が使用する (標準 Javadoc) 標準 ISO-8601 形式

  • 値と単位が結合された、より読みやすい形式 (10s は 10 秒を意味します)

次の例を考えてみましょう。

  • Java

  • Kotlin

import java.time.Duration;
import java.time.temporal.ChronoUnit;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DurationUnit;

@ConfigurationProperties("my")
public class MyProperties {

	@DurationUnit(ChronoUnit.SECONDS)
	private Duration sessionTimeout = Duration.ofSeconds(30);

	private Duration readTimeout = Duration.ofMillis(1000);

	// getters / setters...

	public Duration getSessionTimeout() {
		return this.sessionTimeout;
	}

	public void setSessionTimeout(Duration sessionTimeout) {
		this.sessionTimeout = sessionTimeout;
	}

	public Duration getReadTimeout() {
		return this.readTimeout;
	}

	public void setReadTimeout(Duration readTimeout) {
		this.readTimeout = readTimeout;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit

@ConfigurationProperties("my")
class MyProperties {

	@DurationUnit(ChronoUnit.SECONDS)
	var sessionTimeout = Duration.ofSeconds(30)

	var readTimeout = Duration.ofMillis(1000)

}

30 秒のセッションタイムアウトを指定するには、30PT30S30s はすべて同等です。500ms の読み取りタイムアウトは、500PT0.5S500ms のいずれかの形式で指定できます。

サポートされている任意のユニットを使用することもできます。

  • ns ナノ秒

  • us マイクロ秒

  • ms ミリ秒

  • s 秒

  • m 分

  • h 時間

  • d 日

デフォルトの単位はミリ秒であり、上記のサンプルに示すように、@DurationUnit を使用してオーバーライドできます。

コンストラクターバインディングを使用する場合は、次の例に示すように、同じプロパティを公開できます。

  • Java

  • Kotlin

import java.time.Duration;
import java.time.temporal.ChronoUnit;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.boot.convert.DurationUnit;

@ConfigurationProperties("my")
public class MyProperties {

	// fields...
	private final Duration sessionTimeout;

	private final Duration readTimeout;

	public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
			@DefaultValue("1000ms") Duration readTimeout) {
		this.sessionTimeout = sessionTimeout;
		this.readTimeout = readTimeout;
	}

	// getters...

	public Duration getSessionTimeout() {
		return this.sessionTimeout;
	}

	public Duration getReadTimeout() {
		return this.readTimeout;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import org.springframework.boot.convert.DurationUnit
import java.time.Duration
import java.time.temporal.ChronoUnit

@ConfigurationProperties("my")
class MyProperties(@param:DurationUnit(ChronoUnit.SECONDS) @param:DefaultValue("30s") val sessionTimeout: Duration,
		@param:DefaultValue("1000ms") val readTimeout: Duration)
Long プロパティをアップグレードする場合、ミリ秒でない場合は必ず単位を定義してください(@DurationUnit を使用)。そうすることで、より豊富なフォーマットをサポートしながら、透過的なアップグレードパスが提供されます。

期間の変換

時間ベースの期間に加えて、Spring Boot は java.time.Period 型でも機能します。アプリケーションのプロパティでは、次の形式を使用できます。

  • 通常の int 表現 (@PeriodUnit が指定されていない限り、デフォルトの単位として日を使用する)

  • java.time.Period が使用する (標準 Javadoc) 標準 ISO-8601 形式

  • 値と単位のペアが結合されたより簡単な形式 (1y3d は 1 年 3 日を意味します)

次の単位は、単純な形式でサポートされています。

  • y 年

  • m 月

  • w 週

  • d 日

java.time.Period 型は実際には週数を格納しません。これは「7 日」を意味するショートカットです。

データサイズの変換

Spring Framework には、サイズをバイト単位で表す DataSize 値型があります。DataSize プロパティを公開する場合、アプリケーションプロパティで次の形式を使用できます。

  • 通常の long 表現 (@DataSizeUnit が指定されていない限り、デフォルトの単位としてバイトを使用)

  • 値と単位が結合された、より読みやすい形式 (10MB は 10 メガバイトを意味します)

次の例を考えてみましょう。

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

@ConfigurationProperties("my")
public class MyProperties {

	@DataSizeUnit(DataUnit.MEGABYTES)
	private DataSize bufferSize = DataSize.ofMegabytes(2);

	private DataSize sizeThreshold = DataSize.ofBytes(512);

	// getters/setters...

	public DataSize getBufferSize() {
		return this.bufferSize;
	}

	public void setBufferSize(DataSize bufferSize) {
		this.bufferSize = bufferSize;
	}

	public DataSize getSizeThreshold() {
		return this.sizeThreshold;
	}

	public void setSizeThreshold(DataSize sizeThreshold) {
		this.sizeThreshold = sizeThreshold;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.convert.DataSizeUnit
import org.springframework.util.unit.DataSize
import org.springframework.util.unit.DataUnit

@ConfigurationProperties("my")
class MyProperties {

	@DataSizeUnit(DataUnit.MEGABYTES)
	var bufferSize = DataSize.ofMegabytes(2)

	var sizeThreshold = DataSize.ofBytes(512)

}

10 メガバイトのバッファーサイズを指定するには、10 と 10MB は同等です。256 バイトのサイズしきい値は、256 または 256B として指定できます。

サポートされている任意のユニットを使用することもできます。

  • B バイト

  • KB キロバイト

  • MB メガバイト

  • GB ギガバイト

  • TB テラバイト

デフォルトの単位はバイトであり、上記のサンプルに示すように @DataSizeUnit を使用してオーバーライドできます。

コンストラクターバインディングを使用する場合は、次の例に示すように、同じプロパティを公開できます。

  • Java

  • Kotlin

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.DefaultValue;
import org.springframework.boot.convert.DataSizeUnit;
import org.springframework.util.unit.DataSize;
import org.springframework.util.unit.DataUnit;

@ConfigurationProperties("my")
public class MyProperties {

	// fields...
	private final DataSize bufferSize;

	private final DataSize sizeThreshold;

	public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
			@DefaultValue("512B") DataSize sizeThreshold) {
		this.bufferSize = bufferSize;
		this.sizeThreshold = sizeThreshold;
	}

	// getters...

	public DataSize getBufferSize() {
		return this.bufferSize;
	}

	public DataSize getSizeThreshold() {
		return this.sizeThreshold;
	}

}
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.bind.DefaultValue
import org.springframework.boot.convert.DataSizeUnit
import org.springframework.util.unit.DataSize
import org.springframework.util.unit.DataUnit

@ConfigurationProperties("my")
class MyProperties(@param:DataSizeUnit(DataUnit.MEGABYTES) @param:DefaultValue("2MB") val bufferSize: DataSize,
		@param:DefaultValue("512B") val sizeThreshold: DataSize)
Long プロパティをアップグレードする場合、バイトでない場合は必ず単位を定義してください(@DataSizeUnit を使用)。そうすることで、より豊富なフォーマットをサポートしながら、透過的なアップグレードパスが提供されます。

@ConfigurationProperties 検証

Spring Boot は、Spring の @Validated アノテーションが付けられている場合、@ConfigurationProperties クラスを検証しようとします。JSR-303 jakarta.validation 制約アノテーションを構成クラスで直接使用できます。これを行うには、次の例に示すように、準拠する JSR-303 実装がクラスパス上にあることを確認してから、フィールドに制約アノテーションを追加します。

  • Java

  • Kotlin

import java.net.InetAddress;

import jakarta.validation.constraints.NotNull;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {

	@NotNull
	private InetAddress remoteAddress;

	// getters/setters...

	public InetAddress getRemoteAddress() {
		return this.remoteAddress;
	}

	public void setRemoteAddress(InetAddress remoteAddress) {
		this.remoteAddress = remoteAddress;
	}

}
import jakarta.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import java.net.InetAddress

@ConfigurationProperties("my.service")
@Validated
class MyProperties {

	var remoteAddress: @NotNull InetAddress? = null

}
@Validated を使用して構成プロパティを作成する @Bean メソッドにアノテーションを付けることにより、検証をトリガーすることもできます。

ネストされたプロパティに対して検証が常にトリガーされるようにするには、プロパティが見つからない場合でも、関連付けられたフィールドに @Valid のアノテーションを付ける必要があります。次の例は、前述の MyProperties の例に基づいています。

  • Java

  • Kotlin

import java.net.InetAddress;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

@ConfigurationProperties("my.service")
@Validated
public class MyProperties {

	@NotNull
	private InetAddress remoteAddress;

	@Valid
	private final Security security = new Security();

	// getters/setters...

	public InetAddress getRemoteAddress() {
		return this.remoteAddress;
	}

	public void setRemoteAddress(InetAddress remoteAddress) {
		this.remoteAddress = remoteAddress;
	}

	public Security getSecurity() {
		return this.security;
	}

	public static class Security {

		@NotEmpty
		private String username;

		// getters/setters...

		public String getUsername() {
			return this.username;
		}

		public void setUsername(String username) {
			this.username = username;
		}

	}

}
import jakarta.validation.Valid
import jakarta.validation.constraints.NotEmpty
import jakarta.validation.constraints.NotNull
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import java.net.InetAddress

@ConfigurationProperties("my.service")
@Validated
class MyProperties {

	var remoteAddress: @NotNull InetAddress? = null

	@Valid
	val security = Security()

	class Security {

		@NotEmpty
		var username: String? = null

	}

}

configurationPropertiesValidator という Bean 定義を作成して、カスタム Spring Validator を追加することもできます。@Bean メソッドは static として宣言する必要があります。構成プロパティバリデーターは、アプリケーションのライフサイクルの非常に早い段階で作成され、@Bean メソッドを静的として宣言すると、@Configuration クラスをインスタンス化せずに Bean を作成できます。そうすることで、早期のインスタンス化によって引き起こされる可能性のある問題を回避できます。

spring-boot-actuator モジュールには、すべての @ConfigurationProperties Bean を公開するエンドポイントが含まれています。Web ブラウザーで /actuator/configprops を指すか、同等の JMX エンドポイントを使用します。詳細については、"本番対応機能" セクションを参照してください。

@ConfigurationProperties 対 @Value

@Value アノテーションはコアコンテナー機能であり、型安全な構成プロパティと同じ機能を提供しません。次の表は、@ConfigurationProperties および @Value でサポートされている機能をまとめたものです。

フィーチャー @ConfigurationProperties@Value

緩いバインディング

はい

限定的 ( 以下の注を参照してください)

メタデータのサポート

はい

いいえ

SpEL 評価

いいえ

はい

@Value を使用する場合は、標準形(小文字のみを使用する kebab-case)を使用してプロパティ名を参照することをお勧めします。これにより、Spring Boot は、@ConfigurationPropertiesバインドを緩和した場合と同じロジックを使用できるようになります。

例: @Value("${demo.item-price}") は、application.properties ファイルから demo.item-price および demo.itemPrice フォームを取得し、システム環境から DEMO_ITEMPRICE を取得します。代わりに @Value("${demo.itemPrice}") を使用した場合、demo.item-price および DEMO_ITEMPRICE は考慮されません。

独自のコンポーネントの構成キーのセットを定義する場合は、@ConfigurationProperties でアノテーションされた POJO にグループ化することをお勧めします。これにより、独自の Bean に注入できる構造化された型安全なオブジェクトが提供されます。

アプリケーションプロパティファイルからの SpEL 式は、これらのファイルを解析して環境にデータを取り込むときに処理されません。ただし、@Value で SpEL 式を記述することは可能です。アプリケーションプロパティファイルのプロパティの値が SpEL 式の場合、@Value を介して消費されたときに評価されます。