$30 off During Our Annual Pro Sale. View Details »

Spring Boot 3.0へのアップデートのハマり所 / Findings in Migrating our Application to Spring Boot 3.0

Spring Boot 3.0へのアップデートのハマり所 / Findings in Migrating our Application to Spring Boot 3.0

どのようなフレームワークやライブラリも、大きなアップデートへの対応は大変です。今回のSpring Bootのメジャーアップデートについても実際にやってみて初めて気づいたところや対応に苦労した事がたくさんありました。本セッションでは、Spring Bootを利用しているLINEの実際のプロダクトを題材にして、どのようなハマり所があったかを解説します。
このセッションを聞けば、みなさんがversion upするときに助けになるかもしれません。

森田 大翼 / LINE株式会社
2021年にLINEに入社し、以後サーバーサイドエンジニアとしてLINE DMPの開発に従事。それ以前はSD-WANサービスのバックエンド開発、OSSコミュニティ(OpenStack)のコミッターとしての活動などを経験。

※こちらの資料は以下イベントでの発表内容です。
https://springfest2023.springframework.jp/

LINE Developers
PRO

March 17, 2023
Tweet

More Decks by LINE Developers

Other Decks in Technology

Transcript

  1. MORITA Daisuke
    2023.03.17
    Spring Boot 3.0 へのアップデートのハマり所

    View Slide

  2. Speaker
    2021:LINE⼊社
    • サーバーサイドエンジニアとしてLINE DMP
    の開発に従事(Java, Spring Boot)
    それ以前
    • SD-WANサービスのバックエンド開発を4年
    ほど(使⽤⾔語:Go)
    • OpenStackのOSSコミッター&導⼊サポート
    を3年ほど(使⽤⾔語:Python)
    森⽥ ⼤翼 MORITA Daisuke
    LINE/DMP Devチーム

    View Slide

  3. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードはなぜ必要?
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  4. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードはなぜ必要?
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  5. Spring Boot 3.0
    • およそ5年ぶりのメジャーアップデート
    • Spring Boot 2 系の OSS support は 2023年11⽉に終了
    • Boot 2.7 のOSS Supportは1.5年で、通常より半年⻑く設定されている
    ※出典:https://spring.io/projects/spring-boot#support

    View Slide

  6. OSS Support バージョンを追従しないことのリスクは?
    • バグフィックス、セキュリティアップデートがコミュニティでサポートされなくなります
    • 例: CVE-2022-22965 (Spring4Shell) 脆弱性への対応
    • 2022-03-30: Spring Framework でリモートコード実⾏が可能な脆弱性が話題に上がる
    • 2022-03-31: Spring Team は脆弱性を修正する Spring Framework 5.3.18, 5.2.20 を公開
    • 加えて、Spring Framework 5.3.18 に dependency を持つ Spring Boot 2.5.12, 2.6.6
    を公開
    • Spring Boot 2.4.x, 2.3.x などは OSS Support 外であったため、対応されませんでした
    • 脆弱性の条件に当たる場合、各⾃で Workaround 等の対応を取るしかなくなってしまう
    なので、OSS support に追従する事は⾮常に⼤切です

    View Slide

  7. もちろん Spring Boot 3.0 の新しい便利な機能も使えます
    • AOT & Native サポート with GraalVM
    • Observability with Micrometer and Micrometer Tracing
    • Jakarta EE 10 (9+) のサポート
    • Java 17 の機能をフルに活⽤
    • etc...
    このセッションでは、新しい機能に関する事項は扱いません

    View Slide

  8. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードはなぜ必要?
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  9. LINE DMP についてサクッとご紹介
    • DMP = Data Management Platform (Web広告の⽂脈で⼀般に使われている⽤語)
    LINEサービス
    利⽤履歴
    クライアント
    の顧客リスト
    Web⾏動履歴
    推定属性
    DMP
    LINE広告
    LINE公式アカウント
    バッチ
    アップロード
    ストリーム
    ターゲ
    ティング
    に活⽤
    • ご興味がある⽅はぜひ以下のサイトから LINE DMP の情報を参照してください
    • https://linecorp.com/ja/career/lp/media/Dev4

    View Slide

  10. LINE DMP は Spring Boot で開発されています
    • LINE DMP は2017年5⽉からSpring Bootを使って開発されています
    • できる限りアップグレードは⾏ってきたが、古い依存バージョンになっているものもある
    • Deprecated なクラスや関数が新しい⽅式に移⾏されないままアップグレードされている
    ものもある
    初期リリース(2017年5⽉)
    Java 8
    Spring Boot 1.5.3
    Gradle 3.5
    2023年3⽉現在
    Java 11.0.13
    Spring Boot 2.7.6
    Gradle 6.9.2

    View Slide

  11. LINE DMP は多くのマイクロサービスが連携して動いています
    • LINE DMP は Gradle マルチプロジェクトを活⽤して開発しています
    • 現在、LINE DMP では 45 のマイクロサービスが動いています
    • 処理⽅法に応じて、様々なミドルウェア等と連携しています
    • もちろん、これらにアクセスするために幾つかのライブラリを利⽤しています
    • 様々なタイプのサービスがあるので、アップグレードに関するいろんなハマりどころを発⾒で
    きました

    View Slide

  12. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードはなぜ必要?
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  13. Spring Boot 3.0 のアップグレードをいよいよ実践する
    • Java 17, Spring Boot 3.0 にとりあえず上げてみて、ビルドエラー&実⾏時エラー等を潰しな
    がら対応していき、1つずつ問題をクリアしていきました
    登壇者が実際にやったこと
    この発表では少し整理して説明します
    • ハマった部分を整理・リストアップしてそれぞれ解説します
    • Spring Boot や周辺ライブラリの公式ドキュメント等を調べると載っている事も多く含ま
    れています

    View Slide

  14. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードはなぜ必要?
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  15. やるべきこと、主要な変更点などが整理されています
    まずは Spring Boot 3.0 Migration Guide を眺めましょう
    Before You Start

    Spring Boot 2.7.x (最新) にアッ
    プグレード

    Java 17以降にアップグレード
    • Spring Security 5.8 にアップグ
    レード
    • Spring Boot 2.x の Deprecation
    をレビュー
    • Dependencies の変更をレビュー
    Upgrade to Spring Boot 3

    Jakarta EE への対応
    • Spring Framework 6.0 の変更の
    レビュー
    • Configuration Propertiesの変更
    への対応
    • ** Changes から関係する変更を
    確認する
    https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide

    View Slide

  16. Maven や Gradle のバージョンも確認しよう
    Spring Boot 2.7.x Spring Boot 3.0.x
    Maven 3.3 or above Maven 3.5 or above
    Gradle 6.8 6.9 and 7.x Gradle 7.x (7.5 or above)
    表:Maven と Gradle のサポートバージョンの違い
    (出典: https://docs.spring.io/spring-boot/docs/current/reference/html/getting-started.html#getting-started.installing.java)
    • LINE DMP は Gradle 6.9.2 を使⽤していたので、アップグレードが必要でした
    • compile や runtime などの設定がついに削除されたので対応が必要です
    (subproject が多いとかなり⼤変)
    • Gradle plugin を利⽤する際は Groovy 3.0.7 以降へのアップグレードも必要

    View Slide

  17. Java 11 から Java 17 の重要な変更点を知っておこう
    • Java 11 から 17 の間に追加された JEP (JDK Enhancement-Proposal) は以下から確認できます
    • https://openjdk.org/projects/jdk/17/jeps-since-jdk-11
    • ⼀番重要な変更は「JEP 403: Strongly Encapsulate JDK Internals」だと思います
    • sun.misc.Unsafe などの重要な内部APIを除き、JDKのすべての内部要素が強くカプセル化さ
    れて隠蔽されます
    • 以下のように、java.nio などの内部packageにはデフォルトでアクセスできなくなります
    • この変更により、古い依存ライブラリのコードが実⾏エラーになる場合があります
    • Java 17 に対応したバージョンに依存ライブラリをアップグレードする事を検討してください

    View Slide

  18. 参考: JEP 403
    • JEP 403 詳細
    • https://openjdk.org/jeps/403
    • 制限される内部API⼀覧
    • https://cr.openjdk.org/~mr/jigsaw/jdk8-packages-denied-by-default
    • Workaround
    • --add-opens のコマンドラインオプションを使⽤して、特定のライブラリに対して⾮パブ
    リックメソッドやフィールドのアクセスを有効化する事ができます

    View Slide

  19. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードの概要
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  20. まず、Java Version を 17 に上げて動かす
    • Spring Boot 2.7.x のまま動かします
    • ついでに、Spring Boot 2.7 で Deprecation になっているものに対応しておきます
    • Java 17 をサポートする Gradle version が 7.3 からなので、Spring Boot 3 に必要な 7.5 まで
    version を上げます
    • Unit Test (Mockito) についても Java 17 で動かす事を試みます

    View Slide

  21. JDK Version を 17 に設定する
    • 各々の環境に合わせて設定してください

    View Slide

  22. Gradle で使⽤するJavaバージョンを 17 に設定する
    • コンパイル、クラス⽣成に使う Java versi
    on を17に指定
    • (現在は toolchain を使うのが推奨)
    コンパイルや実⾏時の Java version を指定

    View Slide

  23. Gradle のアップグレード
    • Gradle Wrapper の場合の Gradle version のアップグレード⾃体は簡単
    • compile や runtime などの設定変更は以下
    の対応表を参考に実施します
    (出典: https://docs.gradle.org/current/userguide/upgrading_version_
    6.html#sec:configuration_removal)
    • api を使う場合は Java Library Plugin の設
    定も必要になります

    View Slide

  24. Groovy のアップグレード
    • Gradle plugin を利⽤する際は Groovy 3.0.7 以降へのアップグレードが必要
    • Groovy の version もアップグレード
    2022-12-10 16:21:16.807 [main] ERROR org.springframework.boot.SpringApplication:824 - Application run failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name
    'groovyMarkupConfigurer' defined in class path resource
    [org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration$GroovyMarkupConfigura
    tion.class]: Invocation of init method failed; nested exception is groovy.lang.MissingPropertyException: No
    such property: classLoader for class: groovy.transform.CompileStatic
    at
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireC
    apableBeanFactory.java:1804)
    実際に Groovy をアップグレードし
    ないと実⾏時エラーが起こった

    View Slide

  25. Spring Boot 2.7 Deprecation への対応

    View Slide

  26. Auto-Configuration Registration
    • Spring Boot 2.7 で Auto-configuration の登録するファイルの形式に変更があった
    • 旧形式 spring.factories ファイル
    • 新形式 spring/org.springframework.book.autoconfigure.AutoConfiguration.imports
    ファイル
    • 旧形式は、Spring Boot 2.7 は Deprecated であったが、Spring Boot 3.0 では削除されたので
    ロードされなくなった
    (出典: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#auto-configuration-files)

    View Slide

  27. LINE DMP で起こった問題
    dmp-xxx-app other-dependency-1
    spring.factories
    XxxAutoConfiguration XxxBean
    implementation
    @Bean
    import
    • dmp のあるサービスがライブラリをインポートしており、そのAutoConfigurationで定義され
    るXxxBeanを使っていた
    • Spring Boot 3.0 にアップグレードした場合、spring.factories ファイルは認識されなくなるの
    で、XxxBean が⾒つからず実⾏時エラーとなった
    BootApplication
    Spring Boot 2.7 では読めるが、
    Boot 3.0 では読めなくなっていた

    View Slide

  28. Auto-Configuration Registration への対応と Workaround
    • ⼀般的には、利⽤ライブラリを開発するチームに auto configuration の新形式の対応を依頼す
    ることになります(あるいは⾃分でPRを出す)
    • Workaround として、⾃⾝のプロジェクトの⽅に META-INF/spring/org.springframework.boo
    k.autoconfigure.AutoConfiguration.imports ファイルを作成し、利⽤するライブラリの Auto co
    nfiguration クラスをリストアップする⽅式でも動かす事ができる

    View Slide

  29. LINE DMP で動作確認したWorkaround
    dmp-xxx-app other-dependency-1
    spring.factories
    XxxAutoConfiguration XxxBean
    implementation
    @Bean
    import
    BootApplication
    spring/org.springframe
    work.book.autoconfigur
    e.AutoConfiguration.im
    ports
    import
    Workaround で新形式で
    AutoConfiguration クラスをインポート!

    View Slide

  30. Spring Security / Spring WebMVC の Deprecated Class
    • Spring Security
    • WebSecurityConfigurerAdapter が Spring Security 5.7.0 で Deprecated になり、6.0 で
    削除される
    • SecurityFilterChain bean を使う⽅法に置き換える
    • Guide: https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconf
    igureradapter
    • Spring WebMVC
    • HandlerInterceptorAdapter が Spring WebMVC 5.3.0 で Deprecated になり、6.0 で削除
    される
    • (Async)HandlerInterceptor を使う⽅法に置き換える
    • Guide: https://github.com/spring-projects/spring-framework/pull/25147

    View Slide

  31. HBase

    View Slide

  32. HBase Connection に関連する WARN / ERROR
    HBase master node addresses
    • HBaseのとコネクションが確⽴せず、あるアプリケーションが正常に起動しない
    InaccessibleObjectException なので「JEP 403」
    による問題が起こっている
    HBaseとのコネクションを確⽴する箇所で
    エラーがループする

    View Slide

  33. HBase の JDK 17 対応状況
    • 現状、HBase は JDK 17 への対応が完了されていません (HBASE-26038)
    • しかし、HBASE-25516 の修正が⼊っているバージョンであれば動作するようです
    • ディストリビューションによってJDKサポートの状況の確認が必要となります
    • Client のアップグレードだけで良いか?Server も必要か?等の確認・検証も必要となります
    • DMP では、client の dependency のアップグレードにより実⾏時エラーの問題が収まった
    事は確認しています
    (出典: https://issues.apache.org/jira/browse/HBASE-26038) (出典: https://issues.apache.org/jira/browse/HBASE-25516)

    View Slide

  34. Unit Test (Mockito)

    View Slide

  35. Mock が Java 17 で適切に動かない場合がある
    • 特に何もコードベースに影響が無さそうな箇所で unit test がJava 17で落ちる現象に遭遇した
    • Mockito.spy が想定通りに動いていない箇所があった
    • (Secure)Random を @Mock アノテーションで作る事ができなくなった
    • Mockito 側も JDK 17 以降で起きる問題の数々を認識している
    • https://github.com/mockito/mockito/issues/2589
    • JEP 403 の影響を⼤きく受けている

    View Slide

  36. Mock が Java 17 で動かない場合の対処法
    • Mockito チームは、mockito-inline の⽅は影響を受けていない事から、Mockito 5.0.0 以降では
    mockito-inline をデフォルトの mockmaker に切り替える事を決定した
    • 従って、Java 17 で Mockito を使った unit test が落ちた場合、以下の対応が有効になる(どち
    らでもOK)
    1. mockito-inline に切り替える
    2. mockito の version を 5.0.0 以降にする
    (出典: https://github.com/mockito/mockito/issues/2589)

    View Slide

  37. 01
    02
    03
    03-1
    03-2
    03-3
    Contents
    Spring Boot 3.0 アップグレードの概要
    「LINE DMP」システム構成の概要
    Spring Boot 3.0 アップグレードの実践
    アップグレード前の事前知識
    Java 17 へのアップグレード
    Spring Boot 3.0 アップグレード

    View Slide

  38. いよいよ、Spring Boot を 3.0.x にアップグレード

    View Slide

  39. Jakarta EE

    View Slide

  40. Java EE 8 -> Jakarta EE 10 (9+)
    • Java EE の後継 Jakarta EE に移⾏する事が必須になった (javax.* -> jakarta.*)
    • Gradle/Maven Dependencyの変更 (例)
    • javax.validation:validation-api -> jakarta.validation:jakarta.validation-api
    • javax.annotation:javax.annotation-api -> jakarta.annotation:jakarta.annotation-api
    • Package名変更 (例)
    • javax.validation.* -> jakarta.validation.*
    • javax.servlet.* -> jakarta.servlet.*
    ひたすら置換して対応する!

    View Slide

  41. Upgraded Dependencies

    View Slide

  42. Dependency の Upgrade に伴う Breaking Changes
    • Caffeine (com.github.ben-manes.caffeine:caffeine) 2.9.3 -> 3.1.4
    • StatsCounter interface の recordEviction メソッドの引数に変更があった
    • CacheStats のコンストラクタが private になった(代わりに of メソッドを使う)

    View Slide

  43. Boot 3 に直接依存しないライブラリに問題が起こる場合も
    • MyBatis Spring-Boot-Starter
    • SqlSessionFactory の bean 作成時に NoClassDefFoundError が発⽣
    • Spring Boot 3 に対応した version 3.0.0 以降にアップグレードする必要がある
    • 部署内共有ライブラリ
    • メソッド引数に javax.servlet.http.HttpServletRequest, HttpServletResponse を渡して
    いるため、Jakarta EE に対応する必要がある
    • 共有ライブラリなので、version 戦略や artifact を boot2, boot3 で分けるなどの戦略が必要
    (出典: https://github.com/mybatis/spring-boot-starter)

    View Slide

  44. Jetty

    View Slide

  45. Jetty を利⽤している場合
    • LINE DMP では歴史的経緯で Jetty を Java Servlet コンテナとして利⽤している
    • Jetty の最新版メジャーリリースは 11 だが、これは Servlet 6.0 に対応していない
    • 従って、Servlet API 5.0 にダウングレードして Jakarta EE 9 の Runtime で動作させる必
    要がある
    (出典: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#jetty)

    View Slide

  46. Jetty を利⽤する場合、Unit Test で問題が⽣じる
    • @SpringBootTest のテストを実⾏すると、NoClassDefFoundError が⽣じた
    • このエラーについては、Github上で Open な議論がある
    • Servlet が関わる mock は Servlet API 6.0 を要求するが、Jetty が Servlet 5.0 を要求する
    のでテストが失敗している
    • 現在の提案されている workaround としては、Jakarta Servlet を 6 に戻し、jetty-server
    version を 11 の最新にする事である。(⼀旦、LINE DMPもこれで動いてはいる)
    • 但し、公式 document に無い設定なので闇雲に信じる事は危険
    • Testを⼀旦 Disable する、Jetty 12 を待つ、などの検討が別途必要になる
    https://github.com/spring-projects/spring-boot/issues/33044

    View Slide

  47. Unit Test (RestTemplate)

    View Slide

  48. (Test)RestTemplate を⽤いた unit test が失敗した
    • 301 MOVED_PERMANENTLY を確認するテストケースが、200 OK となり assertion error
    で失敗した
    • Apache HTTP Client であれば、リダイレクト追跡をしないので、リダイレクトをテスト
    できる
    • デバッグしたところ、spring-boot-test 3.0.0 で実⾏した時の TestRestTemplate の http ク
    ライアントが okhttp に変わっていた事を確認した
    • Spring Boot 2.7 の段階では、Apache HTTP Client が使われていた
    okhttp になっている!

    View Slide

  49. Apache HTTP Client のサポートバージョンが変わっていた
    • Spring Framework 6.0 より、Apache HTTP Client 5 に置き換えられていた事が理由だった
    • コードを確認するとApache HTTP Client 5 が⾒つからない場合、okhttp を使うようなプ
    ログラムとなっていた(次ページを参照)
    • testImplementation にApache HTTP Client 5の dependency を追加して対応した
    (出典: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#apache-httpclient-in-resttemplate)

    View Slide

  50. Apache HTTP Client は client5
    を指定している
    Apache HTTP Client -> Okhttp
    Client の優先順でセットし
    ている

    View Slide

  51. 終わりに

    View Slide

  52. 今回の発表のおさらい
    • LINE DMPという実アプリケーションを題材に Spring Boot のメジャーアップグレードを、ビ
    ルド、起動、基本的な動作確認、ユニットテスト実⾏まで⾏いました
    • 単に1つのライブラリのアップグレードという枠を超え、様々な事に対応する必要があること
    が明らかになりました
    • (Gradle のアップグレード)
    • Java 17 への対応
    • Jakarta EE 10 への対応
    • 削除された機能のマイグレーション
    • 依存バージョンのアップグレード
    • 利⽤しているモジュールに固有で存在する問題

    View Slide

  53. これからSpring Boot 3へのアップグレードを進める⽅へ
    • やっぱり Boot 2.7 -> 3.0 や Framework 等の変更点はほどほどに調べておいた⽅が良いです
    • どのような変更があるかを事前に知っておくと、ハマった時の調査に当たりが付く
    • とはいえ、⾃分のプロダクトに関係するか・しないかの⾒極めは難しい
    • なので、ハマってみないと気づかない問題もやはり多い
    • 実際に⼿を動かして、変更すべき点が分かってきたら、何の影響かを整理した⽅が良いです
    • Java version upgrade に起因するのか?
    • 削除された Deprecated な機能への対応か?
    • Spring Boot 3 の変更に起因するのか?
    • その上で、マイグレーションのステップを整理すると、無駄なく安全に移⾏できると思います

    View Slide

  54. Spring Boot 2.7 のEOLは2023年11⽉ですが、移⾏は計画的に

    View Slide

  55. THANK YOU

    View Slide