Gradleを使ってビルドしているSpring BootのアプリケーションをJava9に移行してみた話
こんにちは、バージョンアップおじさんをやっている齋藤です。
今日は自分が担当しているソフトウェアの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のアプリケーションを立ち上げることができました。 いくつか問題はまだまだありますが・・・
アップデートは頑張っていきましょう。