Spring Boot 3.0を試してみた

「NSSOL Advent Calendar 2022」の3日目です。急遽書くことにしたので、12月末まで徐々に記事を成長させていきたいと思います。(言い訳)

# 前書き

2022年11月24日に待望のSpring Boot 3.0がリリースされましたね。Spring Boot 2.0のリリースが2018年3月1日だったので、5年弱ぶりのメジャーバージョンアップということになります。その他のサイトでも既に紹介されていますが、公式サイト・GitHubの説明を踏まえて今回はいろいろと試していきます。

# Spring Boot 2と比べて何が変わったか

簡単に重要度に星を付けてみました。(個人的評価です)

- 【★★★】Java 17 Baseline and Java 19 Support
- 【★★★】Third-party Library Upgrades
- 【★★】GraalVM Native Image Support
- 【★★】Log4j2 Enhancements
- 【★】Improved @ConstructorBinding Detection
- 【★】Micrometer Updates
- 【★★】Prometheus Support
- 【★】More Flexible Auto-configuration for Spring Data JDBC
- 【★】Enabling Async Acks with Apache Kafka
- 【★★】Elasticsearch Java Client
- 【★】Auto-configuration of JdkClientHttpConnector
- 【★】@SpringBootTest with Main Methods

Java 17以上の環境から利用可能なのがやはり一番インパクトが大きいですね。
Spring Boot 2系ではJava 16まではサポートしていたので、Java 17を採用する場合は必然的にSpring Boot 3.0以上を選択することになります。

また、GraalVM Native Imageをサポートすることによって、省メモリ、起動時間の短縮を実現するそうです。導入はとても簡単で、buildpackを使ってビルドするか、Maven/Gradle等のビルドツールで以下のコマンドを追加すればよいようです。詳しく知りたい方は[公式サイトのここのページ](https://docs.spring.io/spring-boot/docs/3.0.0/reference/html/native-image.html)を参照してみてください。

```
# Maven
mvn -Pnative native:compile

# Gradle
gradle nativeCompile
```

# Spring Boot 2系からのアップグレード

公式のGitHubに詳細は紹介されているので、主なポイントだけ補足します。
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

## 事前準備
- Spring Boot 2.7系の最新にアップグレード
- 依存関係の確認
    Spring boot公式以外から提供されているライブラリは特に注意。
- Spring Securityのアップグレード
    Spring Security 5.8にアップグレードしてからSpring Security6.0にアップグレードするのが推奨
- Javaランタイムの確認
    Java 8はサポート対象外になっています。Java 17以上にアップグレードしましょう。
- 非推奨クラス・メソッドの確認

## アップグレード作業

- spring-boot-properties-migratorをMaven/Gradleの依存関係に追加
    application.properties/application.ymlに定義されているプロパティの名称が更新されます。
    アップグレードが完了したら、依存関係から除くことを忘れないように。

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

# Gradle
runtime("org.springframework.boot:spring-boot-properties-migrator")
```

- 影響を受けるソースコードを修正します。変更が多岐にわたるので、手作業で修正していく場合は注意が必要です。
    - 【★★★】Spring Framework 6.0
    - 【★★★】Jakarta EE
    - 【★★★】Core Changes
    - 【★★★】Web Application Changes
    - 【★★】Actuator Changes
    - 【★★】Micrometer and Metrics Changes
    - 【★★★】Data Access Changes
    - 【★★★】Spring Security Changes
    - 【★★】Spring Batch Changes
    - 【★★】Spring Session Changes
    - 【★★】Gradle Changes
    - 【★★】Maven Changes
    - 【★】Dependency Management Changes

- もしマイグレーション対象が多くある等、極力手作業は排除したい場合は、以下のサイトで紹介されているようにOpenRewriteを利用する方法や、それを拡張したSpring Boot Migrator(SBM)もあるようです。もし試された方がいれば感想を教えてほしいです。
https://zenn.dev/cypher256/articles/b6e27b0556d012
https://github.com/spring-projects-experimental/spring-boot-migrator

Webアプリケーションでは、GetMapping/PostMapping/RequestMappingで指定するURLのパターンマッチングのデフォルトの挙動が少し変わるようです。

従来は、最後のスラッシュを書かなくても、さもスラッシュがあるかのような挙動をさせることが可能でした。今後は明示的に設定を変更するか、以下のように実装する必要があります[^1]。

```
@RestController
public class MyController {

  // 以下のように記載する
  @GetMapping({"/some/greeting","/some/greeting/"})
  public String greeting {
    return "Hello";
  }
}
```

また、Jakarta EE 9/10を利用することになる為、パッケージ名の修正が必要になります。このあたりの事例が分かりやすいです。
https://developer.mamezou-tech.com/blogs/2022/09/25/ready-to-ee10/

Spring Security 6.0に変更するにあたってのマイグレーションガイドは[こちら](https://docs.spring.io/spring-security/reference/migration/index.html)です。ざっと見たところでは、それほど影響を受けそうな変更はなさそうでした。ただ、[認証(Authentication)](https://docs.spring.io/spring-security/reference/migration/servlet/authentication.html)の部分は要注意です。

> Default authorities for oauth2Login()
> In Spring Security 5, the default GrantedAuthority given to a user that authenticates with an OAuth2 or OpenID Connect 1.0 provider (via oauth2Login()) is ROLE_USER.
> In Spring Security 6, the default authority given to a user authenticating with an OAuth2 provider is OAUTH2_USER. The default authority given to a user authenticating with an OpenID Connect 1.0 provider is OIDC_USER. If you configured the GrantedAuthoritiesMapper only for the purpose of updating to 6.0, you can remove it completely.

意訳すると、「Spring Security 5では、既定のGrantedAuthority(付与された権限)はROLE_USERでした。Spring Security 6ではOAuth2の場合はOAUTH2_USER, OIDC 1.0の場合はOIDC_USERです。」だそうです。

# Spring Initializrからサンプルアプリを作ってみた

まずは簡単なWebアプリを作ってみましょう。
[Spring Initializr](https://start.spring.io/)にアクセスして、依存ライブラリを指定してGenerateしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/3260e95b-b07c-ac1d-e0f1-101d49af4ae5.png)

2022/12/18時点では、OktaやVMWare Tanzu、GCPのライブラリがSpring Boot 3.0に対応していないようなので注意です。

作ったプロジェクトをお好みのIDEで取り込んで表示します。私は、昔からずっと使っているPleiades All in Oneで開いてみます[^2]。新しい依存ライブラリをダウンロードしてくるので、初回は10分ほどかかります。気長に待ちましょう。[^3]

初期状態だと以下のような形になります。[Spring Initializr クイックスタート](https://spring.pleiades.io/quickstart)を参考にコードを追加して実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/a56aca4a-5663-e0fd-05a8-01542548dc73.png)

hello worldだけを返すメソッドを追加しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/7a852f8c-dbdd-b46f-6cc3-301a95ae4281.png)

Spring bootを実行してみると、ログからSpring Boot 3が起動していることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/c9ae2926-e982-a8f9-6c26-1c0b31eef56b.png)

spring-boot-starter-securityを依存関係に追加しているので、ログイン画面が表示されます。ユーザIDはuser、パスワードはコンソールに出力されている文字列を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/361a1c1f-01a8-eb9c-eb12-f829f29df171.png)

Hello World!と表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333194/9f005670-b891-1271-d7f2-0eaea738e215.png)

ここまでだとSpring Boot 2系とほぼ変わらないので、もう少しSpring Boot 3ならではのサンプルも試してみたいと思います。

# 参考

- https://spring.io/blog/2022/11/24/spring-boot-3-0-goes-ga
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes
- https://www.infoq.com/jp/articles/native-java-graalvm/
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide


[^1]: 設定を変更する方法は非推奨の為、両方にマッチさせたい場合は両方を記載すべきです。
[^2]: Visual Studio Codeもわりと好きです。
[^3]: 依存ライブラリを無駄に追加したせいでもあります。