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ファイルが自動的に展開される。

gradlewとgradle.bat

この2つのファイル、およびコマンドは、どちらもまず、build.gradleとsetting.gradleを参照するのは同じだが、そこから使用されるgradleが変わってくる。

gradlewとは

Gradle Wrapper の実行ファイル。

プロジェクトフォルダ依存で Gradle を実行する。

gradle-wrapper.properties に書かれた URL から Gradle をダウンロードして使用する。

プロジェクトの想定したwrapperの設定を反映するため、gradle.batより、こちらを使用するのがベター。

gradle.batとは

システム(グローバル)にインストールされた Gradle を使用するためのバッチファイル。

gradlew と gradle build の違い

gradlew は build.gradle に記載されている defaultTasks を実行する。

defaultTasks で使用できるタスクは、build.gradle の plugins でインストールしているパッケージに依存する。

gradle buildは、数あるタスクの中の、gradleパッケージのビルドタスクを実行する、という意味。

以下のコマンドで、プロジェクト内で使用できるタスクの一覧を確認できる。

gradlew tasks --all

どのgradleが使われる?

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のキャッシュ

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

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

gradleのキャッシュは以下の2種類がある。

  • グローバルキャッシュ
  • プロジェクトのキャッシュ

グローバルキャッシュ

ユーザー単位のキャッシュ。つまり、ローカルPC内でグローバルに参照される。

依存パッケージも含めたビルド後の資源そのものも保存されている。

保存場所は以下。

%USERPROFILE%\.gradle\caches\

プロジェクトのキャッシュ

タスクの実行結果をキャッシュし、変更点がなければスキップする。

つまりは、依存リポジトリなどは、指定バージョンが変わるなどしていなければ、タスクをスキップし時間を短縮できる。

ここには依存パッケージの実体(ビルド後資源)は含まれていない。

プロジェクトキャッシュは以下に保存される。

プロジェクトのパス/.gradle

gradleの設定

主に以下で設定する。

  • build.gradle
  • gradle.properties
  • gradle/wrapper/gradle-wapper.properties
  • setting.gradle

変数の使用

gradle.properties 内で以下のように変数定義する。

profile=local

build.gradle 内で呼び出す。

"${profile}" getProperty("profile")

環境を切り換える

例えば以下のように変数定義すれば、環境ごとに処理を切り替えることもできる。

■gradle.properties

local.flyway.url=xxx itb.flyway.url=yyy

■build.gradle

flywayUrl = getProperty("${profile}.flyway.url")
// 実行時に変数を上書きする

上記のように profile という変数が用意されている場合、gradlew 実行時に -P オプションを使えば、変数を上書きできる。

gradlew -Pprofile=local
サーバー側で設定した環境変数を使用する

これにより、コマンドでプロファイルを指定すれば、環境別のビルドが実施できるようになる。

システム環境変数の呼び出し

build.gradle で System.getenv() を使用する

Appendix

ビルドしたライブラリの参照

例えば、共通機能を別リポジトリに切り出して開発する場合、ビルドした資源をローカルで参照する設定が必要となる。以下の手順で設定する。

参照先リポジトリを jar ビルド

gradlew clean jar

/build/libs に jar ファイルが作成される。
※ sources.jar も生成される場合、こちらは不要。

参照元リポジトリの build.gradle を編集
※ ファイルパスは / のエスケープが必要となる場合があるので注意する。

dependencies {
  implementation files('jarのファイルパス/XXX.jar')
}

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

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

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

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

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

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

インシデント

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

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

このエラーが出ているということは、おそらく、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:+'

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

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

キャッシュクリア

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

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

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

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

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

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

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

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が存在するか確認する。

まずは、ローカルにキャッシュされていないか、以下を確認する。

%USERPROFILE%\.gradle\caches\

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

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

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

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

キャッシュが無ければ、そもそもgradleがローカルにインストールされていない可能性が高い。

gradeがインストールされていれば、以下に格納されるので、ここにgradleがあるか確認する。

%USERPROFILE%\.gradle\wrapper\dists\

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

ビルド時にSSLException

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

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

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

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

コメント

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