テックブログ

spring-boot-properties-migratorの使い方:変更・廃止された設定を洗い出す

spring-boot-properties-migratorの使い方:変更・廃止された設定を洗い出す

spring-boot-properties-migratorは、Spring Bootのバージョンアップで名前が変わった設定プロパティを起動時に検出し、置換先をログへ表示する移行支援モジュールです。対応する置換先がある場合は実行時に一時的なマッピングも行うため、古い設定を残したままでもアプリが起動することがあります。ただし、設定ファイルそのものを書き換える道具ではありません。診断結果を基に、application.yml、環境変数、コマンドライン引数、外部設定を人が修正し、最後にmigratorを依存関係から外す必要があります。

Spring Boot 4への移行では、設定名の変更だけでなく、機能や自動構成の削除、starterの再編、外部ライブラリ独自設定の変更も起こります。migratorが警告を出さないことは、すべての設定が正しいことを意味しません。本記事ではSpring Boot 4.1.2を基準に、migratorの追加、診断ログの読み方、複数の設定元を漏れなく直す方法、検出できないケース、削除までの完了条件を順番に整理します。

1. properties migratorの役割を理解する

1.1 変更された設定名と置換先を起動時に報告する

migratorの主な役割は、Spring Bootが持つ設定メタデータを使い、環境内に残っている非推奨または名称変更済みのプロパティを見つけることです。対象が見つかると、どのPropertySourceから読み込まれたか、使用中のキー、置換先などを起動ログへ出します。application.propertiesであれば、ファイル名や行番号が表示される場合もあります。

設定プロパティは、Javaコードのフィールド名とは別に、外部からアプリの動作を変えるための公開インターフェースです。バージョンアップでそのインターフェースが変わったとき、古いキーが黙って無視されると、タイムアウト、公開エンドポイント、ログ出力などが意図しない既定値へ戻るおそれがあります。起動できるかだけでなく、設定が実際に有効かを確認する必要があります。

たとえば、古いキーmanagement.endpoints.enabled-by-defaultが残っている環境では、現在の設定モデルに合わせたmanagement.endpoints.access.defaultへの見直しが必要です。機械的に名前だけを置換するのではなく、値の型や意味、既定値も公式の設定一覧で確認します。同じtrueやfalseを移せば同じ動作になるとは限りません。

1.2 一時マッピングは移行完了ではない

置換先が定義されているプロパティについて、migratorは古いキーを新しいキーへ一時的にマッピングします。この仕組みにより、修正前の設定が残っていても起動や検証を続けられる場合があります。しかし、これは移行期間の足場であり、恒久的な互換レイヤーではありません。

一時マッピングに依存すると、migratorを外した瞬間に設定が効かなくなります。また、開発環境では依存を追加していても、本番イメージの依存スコープやビルド設定が異なれば、同じ救済が働かないことがあります。「警告は出るが動いている」状態を許容せず、設定元を修正して警告をゼロにします。

完了の判断は、古いキーを検索して見つからないこと、migratorなしで起動すること、移行前後の動作が一致することの三つで行います。ログが静かになっただけでは、別の設定元が優先されて古いキーが隠れている可能性があります。

1.3 静的解析や万能な設定検査ではない

migratorはアプリの起動時に構築されたEnvironmentを調べます。リポジトリ内の全YAMLを静的に走査するツールではなく、選択されていないプロファイル、デプロイ時だけ注入されるSecret、別環境のConfigMapまですべて自動で確認するわけではありません。

Spring Boot以外のライブラリが独自に読むキーや、自社コードが@Valueで直接参照するキーも、Spring Bootの設定メタデータに情報がなければ置換先を判断できません。削除された機能に置換先がない場合も、単純なリネームとして救済できません。

したがって、migratorは「実際に起動した環境で確認できる有力な診断」と位置付けます。リポジトリ検索、設定台帳、リリースノート、環境別の起動試験と組み合わせて使うことが重要です。

2. 依存関係へ一時的に追加する

2.1 Mavenではruntimeスコープに限定する

Mavenでは、次の依存をpom.xmlへ追加します。Spring Bootのdependency managementを利用している場合は、通常はバージョンを直接書きません。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

runtimeにする理由は、アプリのソースコードからmigratorのクラスを利用するためではなく、起動時の診断だけに使うためです。compileスコープへ広げると、アプリのコードが移行専用モジュールへ依存できてしまい、削除しにくくなります。

追加後は./mvnw dependency:treeで、意図したSpring Bootのバージョンに対応するmigratorが選ばれているか確認します。社内BOMや直接指定したバージョンによって、Spring Boot本体とmigratorの版がずれていないかも見ます。

2.2 GradleではruntimeOnlyを使う

Gradleでは、次のようにruntimeOnlyへ追加します。

dependencies {
    runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
}

Kotlin DSLの場合も考え方は同じです。

dependencies {
    runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
}

依存解決結果は./gradlew dependencies --configuration runtimeClasspathで確認できます。複数モジュール構成では、実際に起動するアプリケーションモジュールのruntimeClasspathへ入っている必要があります。ルートプロジェクトへ書いただけで、対象モジュールへ伝播していないケースに注意します。

2.3 移行専用の変更として分離する

migratorの追加は、設定修正と同じ作業ブランチに置いても構いませんが、最終コミットまで残さないよう管理します。依存追加、診断結果の保存、設定修正、依存削除を別コミットに分けると、レビューで移行専用コードが残っていないか確認しやすくなります。

本番へデプロイして初めて診断する方法は避けます。まず開発環境や検証環境で、本番と同じプロファイル、環境変数名、外部設定の構造を再現します。秘密値そのものを複製する必要はありませんが、どのキーがどの経路から入るかは一致させます。

診断ログをチケットやPRへ貼る場合は、値を含めないよう確認します。migratorの目的はキーの移行であり、パスワードやトークンの共有ではありません。PropertySource名やキーだけでも環境構成が分かる場合があるため、公開範囲にも注意します。

3. 起動して診断ログを読む

3.1 使用するプロファイルを明示する

追加後は、通常の方法でアプリを起動します。

./mvnw spring-boot:run

またはGradleを使います。

./gradlew bootRun

プロファイル別設定がある場合は、対象を明示して起動します。application-local.ymlだけ確認しても、本番用のapplication-prod.ymlに古い設定が残っていれば移行は完了しません。使用可能なプロファイルを一覧にし、少なくとも各設定ファイルが読み込まれる組み合わせを一度は起動します。

外部サービスへ接続できないため起動が最後まで成功しない場合でも、migratorがApplicationFailedEventまで到達すれば診断が出ることがあります。ただし、Environmentが準備される前にJVMやクラスパスの問題で落ちると、診断は実行されません。ログが出ないことと、問題がないことを混同しないでください。

3.2 PropertySource・Key・Replacementを対応させる

名称変更されたキーが見つかると、ログにはおおむね次の要素が表示されます。

The use of configuration keys that have been renamed was found in the environment:

Property source 'Config resource ... [application.properties] ...':
    Key: old.property.name
    Line: 18
    Replacement: new.property.name

Each configuration key has been temporarily mapped to its replacement.

最初に見るのはProperty sourceです。同じキーがapplication.yml、環境変数、コマンドライン引数の複数箇所にあると、優先順位の高い設定だけを直しても、別環境で古い設定が再び有効になる可能性があります。ログに現れた設定元を記録し、リポジトリ内外の管理場所へ紐付けます。

Replacementは修正候補ですが、値をそのままコピーする前に現在版の設定仕様を確認します。名前の変更と同時に、値の型、単位、列挙値、機能の既定動作が変わっている場合があります。設定名だけ新しくして、意味がずれたままにしないことが重要です。

3.3 削除・非互換・未知のキーを分ける

移行時の設定問題は、単純な名称変更だけではありません。少なくとも次の四つに分類します。

分類状態対応
名称変更置換先がある新しいキーへ移し、値の意味を確認する
非推奨まだ動くが将来削除予定現在版で推奨される設定へ移す
削除機能またはキーがなくなった代替機能、starter、コード変更を調べる
未知メタデータに一致しないtypo、独自設定、未導入モジュールを切り分ける

migratorが一時マッピングできるのは主に置換情報があるケースです。削除された機能を自動で再現したり、足りないstarterを追加したりはしません。設定が消えた原因がモジュール再編なら、設定名ではなく依存関係の修正が必要です。

未知のキーを見つけたときに即座に削除するのも危険です。自社の@ConfigurationProperties、第三者ライブラリ、@Valueによる直接参照は、Spring Boot公式メタデータに載らない場合があります。誰が読むキーなのかをコード検索と依存ライブラリの文書で確認します。

4. 設定ファイルを安全に修正する

4.1 application.propertiesは一行ずつ置換する

application.propertiesでは、ログに示された行とキーを確認し、新しいキーへ置き換えます。同じキーがプロファイル別ファイルやテスト用リソースにもないか検索します。

# 修正前
old.property.name=value

# 修正後
new.property.name=value

検索時は完全一致だけでなく、環境変数表記、YAMLの階層表記、プレースホルダーも確認します。たとえばnew.property.name=${NEW_PROPERTY_NAME:default}のような設定では、ファイル内のキーと外部の環境変数の両方が移行対象になり得ます。

修正はカテゴリごとに小さく分けます。Webサーバー、データソース、Actuator、ログなどを一度に変更すると、動作差分が出たときに原因を特定しにくくなります。設定を一群直すたびに起動と該当テストを実行します。

4.2 YAMLは階層と重複キーを確認する

YAMLでは、ドット区切りのキーを階層構造で書けます。置換先を追加するときは、既存の親要素と統合し、同じ親キーをファイル内で重複させないようにします。

management:
  endpoints:
    access:
      default: none

YAMLのインデントを誤ると、見た目は近くても別の構造になります。文字列、数値、真偽値の解釈も変わるため、"off"のように文字列として扱う必要がある値は引用符を維持します。複数ドキュメントを---で分けている場合は、各ドキュメントの有効条件も確認します。

アンカーやマージキーを多用したYAMLは、実際の最終値が追いにくくなります。移行時は、診断対象の設定だけでも展開後の値を確認できるテストを用意します。単にテキスト置換が成功したことではなく、Environmentへ期待値が入ったことを検証します。

4.3 コメントアウトされた古い設定も整理する

migratorはEnvironmentへ読み込まれた値を対象にするため、コメントアウトされた古いキーや、現在選択されないプロファイルの設定は警告に出ないことがあります。コメントは実行時に無効でも、障害対応時に再利用される可能性があります。

古い設定をコメントとして残すなら、なぜ無効なのか、現在の代替は何かを記録します。単に# old.property=trueを残すより、削除してGit履歴へ任せる方が安全な場合が多いです。

サンプル設定、README、デプロイ手順、Helm valuesの例も更新します。実行用ファイルだけ直しても、次回の環境追加で古いテンプレートから問題が再発します。

5. 環境変数と外部設定を移行する

5.1 relaxed bindingを前提に元のキーへ戻す

Spring Bootはrelaxed bindingにより、my.service.timeoutのようなプロパティをMY_SERVICE_TIMEOUT形式の環境変数から受け取れます。ログでは正規化されたプロパティ名が表示されることがあるため、実際のデプロイ定義にある環境変数名へ戻して修正します。

KubernetesのDeployment、Docker Compose、CI/CDの変数、クラウドのアプリ設定、Windowsサービス、systemdなど、注入元は環境によって異なります。リポジトリ検索で見つからない場合は、デプロイ基盤側の設定を確認します。

環境変数名を変更するときは、新旧を同時に残したままにしないことが重要です。PropertySourceの優先順位によって、どちらが使われたか分かりにくくなります。切り替え単位を決め、新しいキーが有効になったことを確認してから古いキーを削除します。

5.2 ConfigMap・Secret・config treeを別に棚卸しする

Kubernetesでは、設定ファイルをConfigMapとしてマウントする方法、環境変数として注入する方法、ファイル名をキーとして読むconfig treeがあります。同じ論理設定でも表現が異なるため、application.ymlだけの検索では不足します。

Secretの値をログへ出す必要はありません。必要なのは、古いキー名が残っていないか、想定するPropertySourceから新しいキーが読まれているか、値の型と単位が正しいかです。検証用の安全な値を使い、キー名と適用結果だけを確認します。

外部設定を管理する別リポジトリがある場合は、アプリ側のPRと同じ変更計画に含めます。アプリを先に更新すると古い設定が無視され、外部設定を先に更新すると旧アプリが読めない可能性があります。一時的に両版を受けられるか、同時リリースが必要かを決めます。

5.3 優先順位による隠れた設定を見つける

Spring Bootでは、コマンドライン引数、Javaシステムプロパティ、環境変数、設定ファイルなど、複数のPropertySourceに優先順位があります。高い優先順位の新しいキーが有効でも、低い優先順位の古いキーが残っていると、環境差や起動方法の変更で再び表面化します。

--debugやActuatorのenvエンドポイントは調査に役立つ場合がありますが、公開範囲とマスキングを必ず確認します。設定値や由来には秘密情報が含まれる可能性があるため、安易に本番で公開してはいけません。

検証では「最終的な値」だけでなく「どの設定元が値を提供したか」を記録します。ローカル、CI、検証、本番相当の各環境で由来が一致していれば、設定の置き忘れを減らせます。

6. migratorで検出できないケースを補う

6.1 @PropertySourceで遅く追加される設定

migratorは起動途中のEnvironmentを分析するため、@PropertySourceなどで後から追加される設定は診断対象に入らない場合があります。公式ドキュメントでも、Environmentへ遅く追加されるプロパティは考慮されない点が注意されています。

独自のdefault.propertiesを@PropertySourceで読む構成では、そのファイルを別途検索し、対応する@ConfigurationPropertiesや@Valueを確認します。可能であれば、Spring Boot標準のConfig Dataとして読み込む構成へ寄せると、読み込み順とプロファイル条件を管理しやすくなります。

起動ログにファイル名が出なかったから対象外と判断せず、アプリが読む設定ファイルの一覧をコードとデプロイ定義から作ります。診断結果と設定台帳の差分が、migratorの死角です。

6.2 独自設定と第三者ライブラリを分ける

自社の@ConfigurationProperties(prefix = "company.payment")や第三者SDKの設定は、各ライブラリが設定メタデータを提供しているかによって検出精度が変わります。Spring Boot公式キーと同じ方法で置換先が出るとは限りません。

独自設定では、設定クラスのフィールド、バリデーション、デフォルト値を確認します。名称変更を行う場合は、旧キーを一定期間受ける互換処理を自社で用意するか、デプロイ設定を同時に更新します。

第三者ライブラリは、Spring Boot 4対応版のリリースノートと設定リファレンスを確認します。ライブラリ自体がまだSpring Boot 4やJakarta EE 11へ対応していない場合、設定名の修正だけでは解決しません。

6.3 設定がない原因を依存関係から調べる

設定メタデータはクラスパス上のモジュールから提供されます。必要なstarterが外れていると、その技術の設定が存在しないように見えることがあります。migratorの警告だけでなく、Mavenのdependency:treeやGradleのdependenciesで対象モジュールが入っているか確認します。

逆に、使わなくなったstarterを外した結果、その設定も不要になったのであれば、置換ではなく削除が正解です。存在しない機能のために別モジュールを追加し直すと、不要な自動構成を戻してしまいます。

判断基準は「古い設定をどう残すか」ではなく、「現在のアプリがその機能を必要としているか」です。必要なら対応starterと新設定へ移し、不要なら設定と依存を一緒に削除します。

7. 設定変更をテストする

7.1 バインド結果を小さなテストで確認する

設定クラスがある場合は、Environmentへ文字列が入ったことだけでなく、@ConfigurationPropertiesへ期待する型と値でバインドされたことをテストします。期間、データサイズ、列挙値、リスト、Mapは、表記変更で意味が変わりやすい項目です。

@SpringBootTest(properties = "sample.client.timeout=3s")
class SampleClientPropertiesTest {

    @Autowired
    private SampleClientProperties properties;

    @Test
    void timeoutIsBound() {
        assertThat(properties.timeout()).isEqualTo(Duration.ofSeconds(3));
    }
}

この例では、3sが3秒としてバインドされることを確認しています。数値だけの3000がミリ秒なのか別単位なのかを暗黙にせず、単位を明示すると移行時の誤読を防げます。

7.2 機能の外部挙動を比較する

設定値が正しく読まれていても、その設定が制御する機能の動作が変わっている可能性があります。HTTPタイムアウトなら遅延応答を使った結合テスト、Actuatorなら公開エンドポイント、ログなら出力形式とレベルを確認します。

移行前の3.5系で、主要な設定と観測可能な結果を記録しておくと比較しやすくなります。すべての内部Beanを固定するのではなく、外部から見える契約と運用上必要な動作を基準にします。

設定変更と同時に依存ライブラリも更新される場合は、どちらが差分を生んだか分けて確認します。設定を一群ずつ直す方針が、ここでも役立ちます。

7.3 全プロファイルの起動確認を自動化する

プロファイルごとに起動する仕組みをCIへ入れると、選択されない設定ファイルの置き忘れを検出しやすくなります。外部サービスはTestcontainers、スタブ、無効化用プロファイルなどを使い、少なくともApplicationContextが設定を読み込めるところまで確認します。

ただし、本番SecretをCIへコピーしてはいけません。キー構造と型を再現した検証用データを用意し、秘密値はCIの安全な管理機能から注入します。

起動確認は「プロセスが終了しなかった」だけでは不十分です。migrator警告、バインドエラー、未知の設定、期待するBean、主要エンドポイントを判定対象に含めます。

8. migratorを削除して移行を完了する

8.1 警告ゼロと古いキーゼロを別々に確認する

すべての対象プロファイルでmigratorの警告が出ないことを確認します。そのうえで、リポジトリ、デプロイ定義、外部設定リポジトリ、運用手順、サンプル設定から古いキーを検索します。

警告ゼロは、実行時に読み込まれた範囲の結果です。古いキーゼロは、将来使われる可能性がある設定を含む静的な確認です。両方が揃って初めて、移行支援へ依存しない状態になります。

診断ログの結果は、キーと設定元だけを移行記録へ残します。秘密値は記録せず、変更PR、確認したプロファイル、テスト結果へリンクします。

8.2 依存を削除して再度起動する

Mavenの依存ブロックまたはGradleのruntimeOnlyを削除します。削除後に依存ツリーを確認し、別モジュールから推移的に入っていないことも確かめます。

./mvnw dependency:tree
./gradlew dependencies --configuration runtimeClasspath

その状態で全プロファイルの起動試験と回帰テストを再実行します。migratorありで成功した結果だけを完了証拠にすると、一時マッピングへ依存したままになる可能性があります。

8.3 完了条件をレビュー項目にする

設定移行の完了条件は次のように整理できます。

  • 対象プロファイルすべてでmigrator警告がゼロ
  • リポジトリと外部設定に古いキーが残っていない
  • 新しいキーの型、単位、意味を公式仕様で確認済み
  • バインドテストと機能テストが成功
  • spring-boot-properties-migratorを依存関係から削除
  • migratorなしで起動、回帰テスト、デプロイ検証が成功
  • 設定テンプレートと運用手順も更新済み

この一覧をPRテンプレートや移行チケットへ入れると、「起動したので完了」という早すぎる判断を防げます。migratorは追加した時点ではなく、不要になって削除できた時点で役割を終えます。

まとめ

spring-boot-properties-migratorは、Spring Boot 4移行で名称変更された設定を起動時に見つけ、置換先と設定元を示すための一時的な診断モジュールです。Mavenではruntime、GradleではruntimeOnlyへ追加し、対象プロファイルごとに起動してログを確認します。

診断結果は、設定ファイルだけでなく、環境変数、ConfigMap、Secret、コマンドライン引数、外部設定へ反映する必要があります。@PropertySourceで遅く追加される設定、独自プロパティ、第三者ライブラリ、削除された機能は検出や自動置換の範囲外になり得ます。

最終的には、古いキーと警告をなくし、新しい設定の意味と外部挙動をテストし、migratorを依存関係から削除します。migratorなしで同じ動作を再現できることが、設定プロパティ移行の完了条件です。

参考リンク