Gradleを使ってビルドしているSpring BootのアプリケーションをJava9に移行してみた話

83件のシェア(ちょっぴり話題の記事)

こんにちは、バージョンアップおじさんをやっている齋藤です。

今日は自分が担当しているソフトウェアのJava9のバージョンアップをしてみました。 基本は下のヌーラボさんが書かれている記事に沿っています。

ヌーラボのアカウント基盤を Java 9 にマイグレーションして起きた問題と解決法

この記事では上記の記事には書かれなかった、gradle周りで起きた、他の内容について記載していこうと思います。

  • Javaのバージョンアップ
  • Gradleのバージョンアップ
  • Gradleで使っているpmdのバージョンアップ
  • Lombokのバージョンアップおよびビルドに必要なJAXBなどの依存関係を追加
  • JVMの起動パラメータの変更
  • Gradleで使っているfindbugsからspotbugsへの移行
  • Dockerで使っているランタイムのイメージを変更

なお、Spring Boot側の問題は特に発生していないので、ここに書いていないのですが 使っているバージョンは Spring Boot 1.5.7です。

Javaのバージョンアップ

まずはJava9を使うのですから、Java9を入れないといけません。 ただ、他のバージョンに切り替えたいこともあると思います。

そのため、私は、SDKMANというツールを使っています。 SDKMANのインストールについてはこちらをご覧ください。

以下のような形で Java9のインストールや切り替えが可能です。 同じようにダウングレードもできるのでご安心ください。

$ sdk install java 9.0.4-oracle # sdk use java 9.0.4-oracle # Java9に切り替え。

また、build.gradleに記述している、Javaのコンパイルターゲットを変更しました。

    // compiler
    sourceCompatibility = 9
    targetCompatibility = 9

gradleのバージョンアップ

gradleのバージョンアップをしましょう。 Java9 のサポートは 4.2.1からになります。 これは以前からバージョンアップをしてきているので、特に問題はありませんでした。

プロジェクトでは、gradle wrapperを使っています。 以下のコマンドを叩いて、gradle wrapperを現状の最新の4.5.1にバージョンアップをしましょう。

$ ./gradlew wrapper --gradle-version=4.5.1

必要に応じて、グローバルに入れているgradleのバージョンアップをしましょう。 アップデート方法はOSや使っているツールで違うと思いますので ここでは割愛しますが、SDKMANによるバージョン管理も可能です。

Gradleで使っている pmd のバージョンアップ

さて、ここまででJava9のビルド環境が整ったわけですが Java8でビルドしていたアプリケーションをビルドしてみましょう。 テストとLintなどが動く、checkタスクを実行します。 (が、testは一旦落ちるので置いておきます。)

./gradlew check -x test

pmdのバージョンアップをしましょう。 内部でASMを使っているので、そちらもバージョンアップする必要があります。

以下のような記述を追加しました。

dependencies {
    ...
    pmd 'net.sourceforge.pmd:pmd-java:5.8.1'
    pmd 'org.ow2.asm:asm:6.0'
}

Lombokのバージョンアップおよびビルドに必要なJAXBなどの依存関係を追加

Lombokのバージョンアップをしましょう。 最新の 1.16.20にしました。

また、Spring Bootの依存の都合もあり、以下の依存関係を追加しました。

dependencies {
    ...
    compile 'javax.xml.bind:jaxb-api:2.3.0'
    compile 'com.sun.xml.bind:jaxb-impl:2.3.0'
    compile 'org.glassfish.jaxb:jaxb-runtime:2.3.0'
    compile 'javax.activation:activation:1.1.1'
}

JVMの起動パラメータの変更

GCログ周りの設定が変わっています。 詳しくは以下のスライドやサイトを参考にしました。

-Xloggc を使っていたところを -Xlog に書き換えました。

また、CMS GCがJava9で deprecatedになっているので、一緒に見直しました。 JVMの起動パラメータの変更は以下のような形になりました。

-  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled \
-  -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 \       
-  -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark \     
-  -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -Xloggc:/var/hoge-fuga/gc_%t_pid%p.log \      
-  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M \
+  -Xlog:gc*=info:/var/hoge-fuga/gc_%t_pid%p.log:time,level,tags:filecount=10,filesize=100m \

Gradleで使っているfindbugsからspotbugsへの移行

findbugsは更新がされていないようなので、spotbugsへ移行しました。 互換性がある程度あるようなので、使うpluginを変えるだけで大丈夫でした。

以下の変更を追加しました。

spotbugs {
    toolVersion = '3.1.1'
    effort = "max"
}

tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
    pluginClasspath = project.configurations.spotbugsPlugins
}

移行については、公式からドキュメントが提供されています。

Dockerで使っているランタイムのイメージを変更

alpineを使っていたのですが、LTSではないからか、Distributionに Java9が登録されていません。 その為、実験のために ひとまず、9-jdk-slimに変更しました。 9-jdk はssl周りでエラーが出たりしたので、ひとまずslimにしています。

spotlessで使っている freshmark を無効にする

現在、うちのプロジェクトでは、spotlessというフォーマッタをgradleプラグインで使っています。 このプラグインを使うことで、eclipseのフォーマッタに適合していないJavaファイルのフォーマットが可能です。 Java9で動かした際に、このプラグインで freshmarkを使ったフォーマッタを有効にしていると、NoClassDefFoundErrorが発生します。

ひとまず不要と判断して無効にしました。Issueは上げています。

これは原因が追いきれていません・・・。 どなたか解決方法など、何か知っていたら教えて欲しいです。

まとめ

今回はモジュールではなく、従来通り、classpath ベースでのビルドですが Java9 でSpring Bootのアプリケーションを立ち上げることができました。 いくつか問題はまだまだありますが・・・

アップデートは頑張っていきましょう。