はじめに
この記事は自分の学習用、備忘録として書いてるものです。
もし内容に間違いなどがあればご指摘ください。
・使用技術
Java21
Spring Boot4.0.6
Spring Batch6.0.3
MySQL
・環境
Mac
この記事の目的
Spring BatchアプリをEclipse上の実行から切り離し、Jarファイルとして作成してコマンドから実行する流れを整理する。
今回は、MavenでJarを作成し、Mac用のrunHelloBatch.shからSpring Batchを実行するところまでをまとめる。
最終的なゴール
最終的には、以下の状態を目指す。
1. Maven packageでJarファイルを作成する
2. target配下にJarが生成されることを確認する
3. Mac用のrunHelloBatch.shを作成する
4. chmodで実行権限を付与する
5. runHelloBatch.shからJarを実行する
6. param1 / param2をJobParametersとして渡す
7. Spring Bootが起動し、バッチが実行されることを確認する
8. ログファイルの出力場所を確認する
今回やりたいこと
今まではEclipseの実行構成からSpring Batchを起動していた。
ただし、実際のバッチ処理では、Eclipseから起動するのではなく、Jarファイルを作成してコマンドやスクリプトから実行することが多いと聞く。
今回の目的は、以下の流れを理解すること。
開発中
→ Eclipseから実行
リリース・実行時
→ Jarを作成する
→ java -jarで実行する
→ 引数でJobParametersを渡す
→ ログを確認する
つまり、Spring Batchアプリを「開発環境上で動くもの」から「外部から実行できるリリース資材」にする練習。
Maven packageでJarを作成する
Spring Bootプロジェクトでは、Mavenのpackageを実行することでJarファイルを作成できる。
Eclipseの場合は、以下のように実行した。
プロジェクトを右クリック
→ 実行
→ Mavenビルド
→ ゴールに package を指定
→ 実行
ターミナルで実行するなら、プロジェクト直下で以下。
./mvnw package
package実行時にテストで失敗した
最初にpackageを実行したとき、ビルドが失敗した。
エラーの内容は、Jar作成そのものではなく、packageの途中で実行されるテストが失敗していた。
エラーの中心は以下。
Tests run: 1, Failures: 0, Errors: 1
さらに原因として、以下が出ていた。
InvalidJobParametersException:
param1の値はnullです。DEV、TEST、PRODのいずれかを指定してください。
これは、テスト実行時にSpring BootのApplicationContextが起動し、その中でSpring BatchのJobも起動しようとしたため。
しかし、今回のテスト実行時にはparam1が渡されていなかった。
その結果、自作のJobParameters Validatorでparam1=nullと判定され、テストが失敗した。
流れとしては以下。
mvn package
→ compile
→ test
→ Spring Bootのテストが起動
→ Batch Jobも自動実行される
→ param1が渡されていない
→ Validatorでエラー
→ test失敗
→ package失敗
対応:Jar作成を優先してテストをスキップした
今回の目的は、まずJarを作成してバッチを実行すること。
そのため、EclipseのMavenビルド設定で以下のようにした。
ゴール: package -DskipTests
プロファイル: 空欄
-DskipTestsを付けることで、テストを実行せずにJar作成まで進める。
./mvnw package -DskipTests
これでBUILD SUCCESSになった。
ここで分かったことは以下。
Javaコードのコンパイルは通っている
Jar作成処理自体も問題ない
⭐️失敗していたのは別の記事で作成して放置していたpackage中に実行されるテストだった
Mavenビルドのプロファイルにpom.xmlを指定しない
間違えた箇所の1つに
最初は、EclipseのMavenビルド設定で「プロファイル」にpom.xmlを指定していた。
しかし、ログには以下のような警告が出ていた。
The requested profile "pom.xml" could not be activated because it does not exist.
pom.xmlはMavenの設定ファイルであって、プロファイル名ではない。
そのため、今回のように特別なMaven profileを作っていない場合、プロファイルの設定は空欄にしないといけなかった
ゴール: package -DskipTests
プロファイル: 空欄
Jarが作成される場所
packageが成功すると、プロジェクト配下のtargetフォルダにJarが作成される。
例。
hello-spring-batch/
├─ src/
├─ pom.xml
└─ target/
└─ hello-spring-batch-0.0.1-SNAPSHOT.jar
Jar名はpom.xmlのartifactIdやversionによって変わる。
そのため、実行前に実際のJar名を確認する。
ls target
Jarを直接実行するコマンド
Jarは以下のように実行できる。
java -jar target/hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
各部分の意味
java
Javaを起動するコマンド。
-jar
Jarファイルを実行する指定。
target/hello-spring-batch-0.0.1-SNAPSHOT.jar
実行対象のJarファイル。
param1=PROD param2=1000
Spring BatchのJobParametersとして渡す値。
Tasklet側で以下のように受け取っている場合、
@Value("#{jobParameters['param1']}")
private String param1;
@Value("#{jobParameters['param2']}")
private String param2;
実行時には以下のように値が入る。
param1 → PROD
param2 → 1000
Windows用の実行ファイルをMac用に置き換える
最初に使っていた実行用テキストはWindows用だった。
set PATH=C:\pleiades-2023\java\21\bin;%PATH%
cd C:\pleiades-2023\workspace\hello-spring-batch\target
java -jar hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
しかし自分んがWindowsではなくMacを使っているため内容を修正する必要があった。
WindowsとMacでは、スクリプトの書き方が違う。
対応関係は以下。
Windowsのset PATH=...
→ Macではexport PATH=...
WindowsのC:\...
→ Macでは/Users/...
Windowsの.bat
→ Macでは.sh
java -jar
→ Macでも同じ
今回改めてMac用に変更した内容が以下の通り。
#!/bin/bash
export PATH=$(/usr/libexec/java_home -v 21)/bin:$PATH
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch/target
java -jar hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
今回のMacでは、以下でJava 21が使えることを確認した。
java -version
出力例。
java version "21.0.5" 2024-10-15 LTS
そのため、export PATH=...は不要だった。
Mac用のrunHelloBatch.sh
最初は以下のようなシェルスクリプトにした。
#!/bin/bash
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch/target
java -jar hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
このスクリプトは、以下の流れで動く。
1. targetフォルダへ移動する
2. target内のJarを指定して実行する
3. param1=PROD param2=1000をJobParametersとして渡す
実行権限を付ける
Macでは、.shファイルを実行するために実行権限が必要になる。
runHelloBatch.shがデスクトップにある場合は、以下。
cd ~/Desktop
chmod +x runHelloBatch.sh
Downloadsフォルダにある場合は、以下。
cd ~/Downloads
chmod +x runHelloBatch.sh
実行する。
./runHelloBatch.sh
Spring Bootのロゴが出ればJarは起動できている
実行後に以下のようなSpring Bootのロゴが出た。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v4.0.6)
この時点で、Jar自体は起動できている。
つまり、少なくとも以下は成功している。
Jarファイルは存在している
java -jarで起動できている
Spring Bootアプリとして読み込まれている
ログファイルがtarget/logに出力された理由
実行後、Eclipseのプロジェクト直下にはログが見当たらなかった。
確認したところ、ログは以下に出力されていた。
hello-spring-batch/target/log/
理由は、runHelloBatch.shでtargetフォルダに移動してからJarを実行していたため。
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch/target
java -jar hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
一方、logback.xmlではログ出力先を以下のようにしていた。
<property name="logDir" value="./log/" />
この./log/の./は、Jarが置いてある場所ではなく、Javaコマンドを実行したときのカレントディレクトリを基準にする。
今回のカレントディレクトリはtarget。
そのため、ログは以下に出た。
hello-spring-batch/target/log/
これは異常ではなく、正常な動き。
プロジェクト直下のlogに出したい場合
プロジェクト直下にログを出したいなら、runHelloBatch.shのcd先をプロジェクト直下にする。
#!/bin/bash
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch
java -jar target/hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
この書き方にすると、./log/の基準がプロジェクト直下になる。
出力先は以下。
hello-spring-batch/log/
この方が分かりやすい。
プロジェクト直下に移動
→ target配下のJarを指定
→ logはプロジェクト直下に出る
自然なrunHelloBatch.shの書き方
今回の学習では、最終的に以下の形が自然。
#!/bin/bash
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch
java -jar target/hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
この書き方にする理由
1. プロジェクト直下を基準にできる
2. target配下のJarを明示的に指定できる
3. logback.xmlの./log/がプロジェクト直下を指す
4. ログの出力場所が分かりやすい
各コードの説明
#!/bin/bash
#!/bin/bash
このファイルをbashで実行するための指定。
シェルスクリプトの先頭に書く。
cd ...
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch
プロジェクト直下へ移動している。
この移動先が、相対パスの基準になる。
例えばlogback.xmlで以下を書いている場合、
<property name="logDir" value="./log/" />
./log/は、ここでcdした場所を基準にする。
java -jar ...
java -jar target/hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
作成したJarを実行している。
target/hello-spring-batch-0.0.1-SNAPSHOT.jarは、Maven packageで作成したJarファイル。
param1=PROD param2=1000は、Spring BatchのJobParameters。
なぜこのように書くといいのか
Eclipseに依存せず実行できる
Eclipseの実行ボタンを使わなくても、Jarとシェルスクリプトがあればバッチを実行できる。
これは実務のバッチ実行に近い。
実行コマンドを固定できる
毎回コマンドを手入力しなくてよい。
./runHelloBatch.sh
これだけで実行できる。
JobParametersを明示できる
実行時に渡す値がスクリプトに書かれているため、どのパラメータで実行したか分かりやすい。
param1=PROD param2=1000
ログの出力場所を制御しやすい
cdする場所を決めることで、./log/の基準も決まる。
cd target
→ target/log/
cd プロジェクト直下
→ プロジェクト直下/log/
この考え方を理解しておくと、ログがどこに出たのか迷いにくい。
注意する箇所
1. packageはテストも実行する
mvn packageはJarを作るだけではない。
途中でテストも実行される。
今回のように、テスト実行時にBatch Jobが自動起動して失敗することがある。
Jar作成を優先するなら、以下でテストをスキップできる。
./mvnw package -DskipTests
ただし、これは一時的な回避策。
本来はテスト側でBatch Jobの自動実行を止めるなど、テストが通るように直すのが自然。
例。
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(properties = "spring.batch.job.enabled=false")
class HelloSpringBatchApplicationTests {
@Test
void contextLoads() {
}
}
contextLoadsの目的は、SpringのApplicationContextが起動できるかの確認。
Job実行テストではないなら、テスト時にBatch Jobを自動実行しないようにするのが分かりやすい。
2. Mavenのプロファイルにpom.xmlを入れない
EclipseのMavenビルド設定で、プロファイルにpom.xmlを入れる必要はない。
pom.xmlはMavenの設定ファイル。
profileを定義していないなら、プロファイルは空欄でよい。
ゴール: package -DskipTests
プロファイル: 空欄
3. Jar名は必ず確認する
Jar名はプロジェクト設定によって変わる。
実行前に以下で確認する。
ls target
実際に出ているJar名に合わせて、java -jarの指定を修正する。
4. Javaバージョンを確認する
今回の環境ではJava 21を使っていた。
java -version
出力例。
java version "21.0.5" 2024-10-15 LTS
Eclipseでは動くのにターミナルでは動かない場合、Javaのバージョン違いが原因になることがある。
5. .shには実行権限が必要
Macでは、シェルスクリプトに実行権限を付ける必要がある。
chmod +x runHelloBatch.sh
実行する。
./runHelloBatch.sh
6. ./log/はJarの場所ではなくカレントディレクトリ基準
ここは特に注意。
logback.xmlに以下を書いている場合、
<property name="logDir" value="./log/" />
./log/は、Jarがある場所ではなく、java -jarを実行した場所を基準にする。
cd target
java -jar xxx.jar
この場合は、
target/log/
に出る。
cd プロジェクト直下
java -jar target/xxx.jar
この場合は、
プロジェクト直下/log/
に出る。
7. Eclipseの表示は自動更新されないことがある
ターミナルからJarを実行してファイルが作成されても、Eclipseの画面にすぐ表示されないことがある。
その場合は、プロジェクトを右クリックして以下を実行する。
Refresh
今回学んだこと
今回の学習で一番重要だったのは、Jar作成とバッチ実行の流れ。
Maven packageでJarを作る
→ java -jarで実行する
→ JobParametersを渡す
→ ログで結果を確認する
また、Jar作成時のエラーも、単に「Jarが作れない」と見るのではなく、どのフェーズで失敗しているかを見る必要がある。
今回の場合は、Jar作成処理ではなく、package中のテストで失敗していた。
まとめ
今回やったことは以下。
1. EclipseのMavenビルドでpackageを実行した
2. テスト失敗により一度BUILD FAILUREになった
3. package -DskipTestsでJar作成を優先した
4. target配下にJarが作成された
5. Windows用のbat相当の処理をMac用のshに置き換えた
6. chmod +xで実行権限を付けた
7. ./runHelloBatch.shでJarを実行した
8. Spring Bootが起動することを確認した
9. ログがtarget/logに出る理由を確認した
10. プロジェクト直下/logに出すならcd先を変えると分かった
今回の理解ポイントは以下。
Jarはリリース資材
mvn packageはJar作成前にテストも実行する
-DskipTestsはテストを実行せずJar作成を優先する指定
java -jarはJarを実行するコマンド
param1=PROD param2=1000はJobParameters
.shはMac用の実行スクリプト
./log/はカレントディレクトリ基準
最終的なMac用スクリプトは以下の形が分かりやすい。
#!/bin/bash
cd /Users/kounoyuuta/Desktop/workspace/SpringBatch/hello-spring-batch
java -jar target/hello-spring-batch-0.0.1-SNAPSHOT.jar param1=PROD param2=1000
参考記事
-
Apache Maven - Introduction to the Build Lifecycle
https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html -
Spring Boot Reference Documentation - Executable Jars
https://docs.spring.io/spring-boot/reference/executable-jar/index.html -
Spring Boot Reference Documentation - Testing
https://docs.spring.io/spring-boot/reference/testing/index.html -
Spring Batch Reference Documentation
https://docs.spring.io/spring-batch/reference/ -
Bash Reference Manual
https://www.gnu.org/software/bash/manual/bash.html