Javaのgradleビルドデプロイ備忘録

Javaはmavenもしくはgradleというビルドツールを使用する。ここではgradleについて扱う。

ビルドの設定はbuild.gradleで行う。

ここで使われている変数は、gradle.propertiesに定義されていることがある。

ビルドコマンド

warやjarファイルとしてビルドする。

基本的にはwarとしてビルドするが、他のリポジトリから読み取られるライブラリとしてビルドする場合にはjarにすることもある。

warファイルにビルドする

gradlew.bat clean build

gradlew.bat buildだけでも良いのだが、cleanでキャッシュクリアしている。

jarファイルとしてビルドする

gradlew clean jar

ビルド時間の短縮

gradlew.bat clean build -x test -x compileTestJava -x check

-x [タスク名]  とすることで、タスクをスキップしてビルド時間を短縮できる。

  • -x test: テストを省略
  • -x compileTestJava: テスト資源のビルドを省略
  • -x check: スタイルチェックを省略(-Xcheckが正かも)

デプロイ

サーバーのwebappsフォルダに、ビルドしたwarファイルを配置する。しかし、root権限でないとwebappsフォルダに直接アクセスできないため、WinSCPなどで直接ファイルを配置することはできない。

そのため、任意のworkフォルダにwarを配置し、RLoginなどのSSHクライアントでwarファイルを移動しなおす。

今回は以下をworkフォルダとする。

/home/ec2-user/work

ファイルを配置したら、以下のコマンドでデプロイする。

cd /opt/tomcat/webapps  // webappsフォルダに移動
service tomcat stop  // tomcat停止
rm -rf appName  // もともとあるアプリを削除
rm -rf appName.war  // もともとあるアプリを削除
cp /home/ec2-user/work/appName.war /opt/tomcat/webapps/  // warファイルを移動
chmod 644 appName.war  // warファイルの権限を修正
service tomcat start  // tomcat起動

warファイルがwebapps配下にある状態でtomcatを起動すると、warファイルが自動的に展開される

ビルドのキャッシュ

ビルドはSpringFrameworkなどのライブラリについても行われるため、初回はかなり長い時間を要する。

2回目以降はキャッシュを参照するため、ビルド時間が短くなる。

しかし、cleanだけではこのキャッシュが更新されず、ビルドエラーを引き起こすケースが良くある。その場合は、物理的にキャッシュを削除することで解消される。

キャッシュはローカルでは以下に保存され、ここで、使用されているパッケージの一覧も確認できる。

C:\Users\username\.gradle\caches\modules\filles-2.1\

eclipseでは、パッケージエクスプローラーの参照ライブラリーを見ると、プロジェクトで使用されているライブラリが一覧で表示される。

各ライブラリの右側に、ローカルのどのファイルを参照しているかが表示されており、上記のキャッシュを見ていることがわかる。

eclipseで実装しているのであれば、以下の手順で参照先を手動で変更することができる。

ビルドパスの構成>
『ライブラリ』タブ>参照しているライブラリを削除  // ここでcacheフォルダを参照していれば削除
『クラスパス』タブ>追加>参照したいライブラリを追加  // 本来参照したい資源に再設定
>適用

インシデント

シンボルを見つけられません

初学者だとこのメッセージだけでは『???』となる。

このエラーが出ているということは、おそらく、1つだけでなく、いくつかのシンボルが見つからないエラーが出ているだろう。

1つのエラーの区切りが分かりづらいが、以下のようなまとまりが1つのエラーについてのメッセージとなる。

C:\〇〇\〇〇\…\〇〇Service.java:12: エラー:シンボルを見つけられません
    SampleImplClass<SampleClass> sampleMethod();
                               ^
  シンボル:  クラス  SampleClass
  場所:  インターフェース  〇〇Service.java

このまとまりで見るとわかりやすい。シンボルが何かは下部に示されていて、そのシンボルが〇〇Service.java内で呼び出されたが、該当のクラスは見つからなかった、ということだ。

結論、たいていの場合は依存関係の不整合であることが多い。

別のAPIやリポジトリを呼び出しているが、呼び出し先のバージョンに誤りがあったために、実装されているはずのクラスが見つからなかった、というような話だ。

gradleでは、依存リポジトリの参照は、build.gradleに以下の形式で書き込まれている。

dependencies {
  api 'jp.co.appname.api:reponame:0.0.111'
}

上記はnexusに依存リポジトリを保存しており、それを参照する設定の例だが、このアプリからreponameというリポジトリの0.0.111バージョンを指定している。

バージョンは特殊な書き方をすることもでき、たとえば以下のように『+』を使用すればバージョン固定ではなく、nexusに保存されている該当リポジトリの最新版を参照する設定となる。

api 'jp.co.appname.api:reponame:+'

このような特殊なバージョン指定をしているときに、特に今回のような不整合が起こりやすい。

正しいバージョンで指定してね。

build.gradleに記載されている変数が見つからない

これはgradle.propertiesとは何なのか、という話に直結する。

gradle.propertiesでは、gradle関連ファイルで使用するプロパティを定義しており、build.gradleで使用されている変数も、このファイルで定義されている。

build.gradleにはimport文など無いので、これを知らないとなんだこの変数??となる。

SSLHandshakeException

gradlewを実行してビルドしようとしたところ、以下のエラーが発生。

Downloading https://services.gradle.org/distributions/gradle-6.0.1-bin.zip
Exception in thread "main" javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

開発環境は、クライアント環境で、webへのアクセスが制限されていた。

gradleパッケージがローカルになかったため、webに取りに行こうとしたところ、webにアクセスできずエラーとなっている。

まずはgradleの状況を確認する。

gradlew --version

gradleの参照設定が正常であれば、これでgradleのバージョンがわかる。

『Downloading https://services.gradle.org/…』みたいな処理が始まった場合は、gradleが見つからず、webに取りに行こうとしてしまっている。

その場合は、ローカルのgradleがどうなっているかを確認する。

gradleは一度でもビルドされると、cacheが作られ、今後はそのcacheを見に行くことでビルド時間を短縮している。

というわけで、gradleには以下の3つの参照経路がある。

  • もともとのgradle
  • cacheされたgradle
  • webにgradleを取りに行く

参照順は以下の通り。

  1. ローカルのキャッシュ(cacheされたgradle):%USERPROFILE%\.gradle\caches\
  2. 無ければプロジェクトの参照設定(webにgradleを取りに行く):[projectname]/gradle/wrapper/gradle-wrapper.properties の distributionUrl …※
  3. それでも見つからなければローカルの本体(もともとのgradle):%USERPROFILE%\.gradle\wrapper\dists\

※このdistributionUrl でgradleのバージョンも指定している。ローカルやNexusのパスを記載して参照することもできるが、たいていは、ローカルに見つからなかった際にwebから取得できるように、gradle公式のURL『https://services.gradle.org/distributions/gradle-x.x.x-bin.zip』を記載している。x.x.xがバージョン指定。

gradleがローカルに存在しない場合

gradleの公式サイトからダウンロードして使用する。

gradleはローカルにあるのに、参照されない場合

プロジェクトの指定しているgradleのバージョン([projectname]/gradle/wrapper/gradle-wrapper.properties のdistributionUrl)が、キャッシュ(%USERPROFILE%\.gradle\caches\)に存在するか確認する。

なければ、distributionUrlを、キャッシュにあるバージョンに書き換えてあげればよい。

ビルド時にSSLException

ビルドしようとしたら以下のエラー。

Caused by: javax.net.ssl.SSLException: Unsupported or unrecognized SSL message

このアプリケーションは、RESTで別のリポジトリと通信しているのだが、そこでSSLエラーが発生しているよう。

application.env.yml で指定している依存リポジトリを参照するURLを、https から http に変更して解消。

Appendix

依存リポジトリのバージョン指定

REST API で通信するような、別で開発している依存リポジトリへの参照があるとき、以下の設定を行うと思う。

  • build.gradle の dependencies でのパッケージ、バージョンの記載
  • application.env.yml での通信先URLの指定

この2つの違いは何なのか。build.gradleのバージョンと、application.env.ymlで指定した通信先にあるリポジトリのバージョンが違った場合、どうなるのか。

もちろんエラーが発生する可能性がある。2つのリポジトリには以下の違いがある。

  • build.gradle で指定したパッケージはビルド時に使用される。
  • application.yml で指定したURLは実際の通信先として使用される。

コメント

タイトルとURLをコピーしました