はじめに

Spring Boot 2系の最終リリースである2.7が2023年11月でOSSサポート終了となったことに伴い、Spring Frameworkを利用する実プロジェクトで活用できる設計・開発標準およびSpringアプリ開発ノウハウ集で公開しているソースコードやドキュメントをSpring Boot 3系に対応するよう修正しました。(Spring Bootのサポート期間については、公式ページで確認できます。)

この記事では、アップグレードの際の主な修正内容について紹介します。これからSpring Boot 3にアップグレードする方に参考にしていただけると幸いです。

前提

主なライブラリのアップグレード前のバージョンおよびアップグレード後のバージョンは以下の通りです。

ライブラリ アップグレード前 アップグレード後
Java 11 17
Spring Boot 2.7.6 3.2.0
Spring Cloud AWS 2.4.2 3.1.0
Nablarch 5u21 6

関連ドキュメント

Spring Bootのアップグレードにあたっては、主に以下のドキュメントを参考にしてアップグレードを実施しました。

Spring Batchは特に変更内容が大きかったため、個別にマイグレーションガイドを参照してアップグレードしました。

Spring Cloud AWSのアップグレードは、以下の記事を参考にしました。

また、Java EEからJakarta EEへの変更についてはNablarchのドキュメントを参考にしました。

これらのドキュメント以外に参照したドキュメントについては、該当箇所で個別に紹介しています。

マイグレーションガイドに従った対応内容

サンプルアプリケーションのアップグレードで必要となった修正を簡単に紹介します。詳細については公式のマイグレーションガイドを参照してください。

共通

  • Java 17でビルドするように修正
  • 依存関係のリスト(spring-boot-starter-parentspring-boot-dependencies)を更新
    • Spring Boot 3.2の依存関係のリスト全量は、Dependency Versionsで確認できます。
  • Jakarta EEを利用するように修正
  • JUnit 4から5へのマイグレーション

バッチ

  • ItemWriterの引数型変更(java.util.Listorg.springframework.batch.item.Chunk
  • ListenerSupport抽象クラスではなくListenerインターフェースを利用するように修正
  • StepExecutionから取得する各種件数の型を修正
    • 件数などの型がintからlongに変更されました。
  • @EnableBatchProcessingを削除
  • JobBuilderStepBuilderの取得方法を修正
  • Spring Batchのメタデータスキーマを更新
  • 自動テストではバッチジョブの自動起動を無効化
    • 複数のバッチジョブが含まれるアプリケーションを起動する場合、実行対象のバッチジョブを明示的に指定しないとエラーになるように変更されました。その影響で、自動テストが失敗するようになりました。
    • 自動テストの実行時には、アプリケーションプロパティにspring.batch.job.enabled=falseを設定するようにして回避しました。

Web、API

  • URL毎の認可設定にmvcMatchersではなくrequestMatchersを使うように修正
  • ReferrerPolicyをLambda DSLで設定するように修正

その他の対応内容

マイグレーションガイドに記載がない、もしくは追加で検討が必要だったなど、アップグレードにあたって注意が必要だと感じた修正内容を紹介します。

JsrJobParametersConverterの削除対応

Spring Batch 5.0でJSR-352関連実装が削除されました。サンプルアプリケーションではJsrJobParametersConverterを利用していたのですが、同等の機能を持つ代替実装が提供されていなかったため、公開されているソースコードを移植して対応しました。

セッション永続化の設定方法変更

Spring 2.7では、アプリケーションプロパティで次のように設定することでセッションの永続化方法を指定することができました。

spring.session.store-type=jdbc

マイグレーションガイドに記載のある通り、Spring Boot 3ではこのプロパティが廃止されました。代わりに依存関係から自動的に永続化方法が選択されます。このため、上記の設定値は削除しました。

選択される永続化方法の優先順位は Spring Session | Web | Spring Boot を参照してください。

依存関係を変更するのは難しいが実行環境によって永続化方法を変更したい場合もあるかと思います。今回の対応の中では、ローカル開発環境にRedisが用意できない場合の対応方法を検討しました。依存関係にRedisが含まれる状態のままで、ローカル環境ではセッションをデータベースに永続化するように変更したかったので、ローカル環境向けのプロファイルに以下のような設定を追加しRedisのAuto Configurationを無効化することで対応しました。

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

Spring Cloud AWSのRDSインテグレーション機能廃止

Spring Cloud AWS 2.xではRDSインテグレーション機能としてフェイルオーバー機能やリードレプリカへの自動切換え機能が提供されていましたが、3.0で廃止されました。同様の機能を持つAWS JDBC Driverが公開されており、代替として利用できるようです。

URLの末尾スラッシュ有無が区別されるようになったことへの対応

Spring Boot 3.0ではURLの末尾スラッシュ有無が区別されるようになり、プロキシなどでURLをリダイレクトする設定をいれるなどの対応が推奨されています。しかし、推奨される対応方法はいずれも影響範囲が広く対応が困難なことも多いと考えられるので、サンプルアプリケーションでは過去のバージョンと同じように末尾スラッシュの有無を区別しないように設定しました。

@Configuration
public class PathMatchConfig implements WebMvcConfigurer {
  @Override public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.setUseTrailingSlashMatch(true);
  }
}

ただし、PathMatchConfigurer#setUseTrailingSlashMatch(boolean)は非推奨であり、今後のリリースで削除される可能性があります。このような対応は一時的なものと考え、最終的にはマイグレーションガイドで推奨されている方式への修正をおすすめします。

日付パースの仕様変更

Spring Boot 3 (Spring Framework 6)では日付のパース仕様が変更され、指定されたフォーマットでのパースに失敗した場合にデフォルトでISO 8601形式にフォールバックするようになりました。

例えば、以下のようにスラッシュ区切りの日付を期待する入力項目に対して2023-12-25という入力値が与えられた場合、Spring Boot 2.xではエラーになりましたがSpring Boot 3.xでは正常にパースされエラーとはならなくなりました。

@DateTimeFormat(pattern = "uuuu/MM/dd")

サンプルアプリケーションではこのような挙動の変更を受容する方針としましたが、以下のようにfallbackPatternsにも同じフォーマットを指定することで過去バージョンと同様の振舞いを維持できます。

@DateTimeFormat(pattern = "uuuu/MM/dd", fallbackPatterns = "uuuu/MM/dd")

Thymeleafの#requestおよび#session削除への対応

Thymeleaf 3.1で、テンプレートファイルで#requestおよび#sessionが利用できなくなりました。サンプルアプリケーションでは、クエリパラメータとセッション属性の取得に利用していたので、それぞれparamおよびsessionを使うように修正しました。

#request.getParameter('error') → param['error']
#session.getAttribute('SPRING_SECURITY_LAST_EXCEPTION') → session['SPRING_SECURITY_LAST_EXCEPTION']

Content-Dispositionヘッダの出力内容変更対応

アプリケーションの動作にはおそらく影響はありませんが、Content-Dispositionヘッダに拡張ファイル名パラメータ(filename*)
が追加されるようになりました。

サンプルアプリケーションとノウハウ集では、自動テストの期待値を修正する必要がありました。

SnakeYAML 2.0対応

Spring Boot 3.1から3.2へのアップグレードで、SnakeYAMLのバージョンが1.33から2.2に更新されました。SnakeYAML 2.0では脆弱性(CVE-2022-1471)修正のため、グローバルタグ(!!~~)でのコンストラクタ呼び出しはデフォルトでは禁止されるようになりました。

サンプルプロジェクトでは、Database RiderのCustom replacerの設定のためにグローバルタグを利用していました。

cacheConnection: false
properties:
  caseSensitiveTableNames: true
  replacers:
    - !!com.github.database.rider.core.replacers.DateTimeReplacer {}
    - !!com.github.database.rider.core.replacers.UnixTimestampReplacer {}
    - !!com.github.database.rider.core.replacers.NullReplacer {}
    - !!com.example.batch.test.SystemDateTextReplacer {}

Spring Boot 3.2へのアップグレード後は、各テストクラスに以下のようなアノテーションを設定するように変更しました。

@DBUnit(replacers = {SystemDateTextReplacer.class}, cacheConnection = false, caseSensitiveTableNames = true)

関連Issue: SnakeYAML 2.x (Spring Boot 3.2) Compatibility | Database Rider

Spring Session JDBCのMockMvc関連不具合対応

Spring Session JDBCを利用している場合、テストコード(AutowireされたMockMvc)とプロダクションコードで異なるHttpSesionを参照してしまうようでした。

サンプルアプリケーションでは二重サブミットが防止されているコントローラに対するテストの際に、トランザクショントークンをMockMvc経由でHttpSessionに格納し、リクエストパラメータとしても設定します。テスト対象のコントローラ(プロダクションコード)ではHttpSessionから取得したトークンとリクエストパラメータのトークンが一致することを確認して二重サブミットを防止しています。MockMvcとコントローラで異なるHttpSessionを参照するようになってしまったため、トークンが一致せずテストが失敗するようになりました。

このため暫定的に、サンプルアプリケーションではテストの際にはJDBCを利用せず、MapSessionRepositoryを設定するように変更し不具合を回避しました。

関連Issue: spring-session-jdbc ignores specified MockMvc request session

アップグレード対応のプルリクエスト

以下に、今回のアップグレードに関連するプルリクエストをまとめています。ソースコードやドキュメントの更新などの参考にしていただけると幸いです。
Springアプリ開発ノウハウ集の関連プルリクエスト
Springサンプルプロジェクトの関連プルリクエスト