Spring Batchはバッチ処理を実装するにあたり、有力なフレームワークであり、一から自分で実装するよりはるかに手軽に実装することが可能です。
バッチ開発をJavaで実装するとなった際は、誰もが導入を検討するでしょう。

Springアプリを使っているプロジェクトならなおさらだね
ここで、Spring Batchの全体像について説明していきます。
Spring Batchの流れ

Spring Batchは主に以下のコンポーネントで構成されます。
- Job Repository
- Job Launcher
- Job
- Step
Job RepositoryはJobやStepを管理しており、定義された設定に基づいて失敗や再試行といったトランザクションを保証します。

デフォルトではインメモリで実行管理するけど、永続化が必要な場合はDBやスキーマを設定しないといけないよ。
ClientからコマンドなどでJobを実行した時に、Job LauncherがJobのパラメータ毎(実行日時など)にJob Instanceを作成します。
Jobは複数実装することが可能で、Job内にも複数のStepに分けて処理が施行されます。
例えば、①DBの初期化を行ってから、②ファイルを読み込んで、③データに変更を加えたり、、などですね。
では、具体的にどのように実装するのでしょうか?
Stepの定義方法
Stepの定義方法が、以下の2つになります。
- Tasklet
- Chunk
ここでは、分かりやすいようにStep1をTasklet、Step2をChunkで実装するパターンについて考えてみましょう。

Tasklet
Step1で定義したTaskletでは、Chunk(データのIO処理など)には当てはまらない処理をしたい場合に利用します。
Spring Batchが提供するインターフェースなので、以下のようにimplementsして使用します。
@Component("jobATasklet")
@Scope("step")
public class jobATasklet implements Tasklet {
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
...
return RepeatStatus.FINISHED;
}
}
Chunk
Step2で定義したChunkは、以下3つのItemをセットで一つのトランザクションとします。
- ItemReader:データの読み込み
- ItemProcessor:業務処理
- ItemWriter:データの書き込み
こちらも、それぞれSpring Batchが提供しているインターフェースなので、以下のようにimplementsして使用します。
public class TestItemReader implements ItemReader<I>, StepExecutionListener {
@Override
public I read() throws Exception {
...
}
}
public class TestItemProcessor implements ItemProcessor<I, O>, StepExecutionListener {
@Override
public O process(I item) throws Exception{
...
}
public class TestItemWriter<T> implements ItemWriter<O>, StepExecutionListener {
@Override
public void write(List<? extends O> items) throws Exception {
...
}
Configurationのやり方
ここまで、Stepの処理内容の実装方法について説明しましたが、Stepの実施手順(順番など)をJob毎に定義する必要があります。その定義の仕方にJavaベースとXMLベースの2種類があります。
これまでの例と同様にStep1をTasklet、Step2をChunkとした場合、それぞれ以下のような実装になります。
Java-based Configuration
@Configuration
@EnableBatchProcessing
public class MyJobConfiguration {
@Bean
public Job jobA(JobRepository jobRepository, Step step1, Step step2) {
return new JobBuilder("jobA", jobRepository)
.start(step1)
.next(step2)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager
transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(jobATasklet(), transactionManager)
.build();
@Bean
public Step step2(JobRepository jobRepository,
PlatformTransactionManager transactionManager) {
return new StepBuilder("step2", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.build();
}
XML-based Config
<job id="jobA" job-repository="jobRepository">
<step id="step1">
<tasklet ref="jobATasklet" transaction-manager="transactionManager"/>
</step>
<step id="step2">
<tasklet transaction-manager="transactionManager">
<chunk reader="itemReader" processor="itemProcessor" writer="itemWriter" commit-interval="10"/>
</tasklet>
</step>
</job>
Listenerとは
ListenerとはJobやStepの実行前後で処理を実装するためのもので、ログの出力やステータスに応じた処理を組み込むことができます。
主に以下の種類があります。
- JobExecutionListener
- StepExecutionListener
- ChunkListener
- Item[Read/Process/Write]Listener
以下はStepExecutionListenerをimplementsした例になります。
@Configuration
public class TestLoggingListener implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
...
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
...
return stepExecution.getExitStatus();
}
}
Jobの実行
以下のapplication.ymlの設定をfalseにしないと、アプリ起動時に自動的にJobが実行されてしまいます。
spring.batch.job.enabled = false
Jobの実行にはJavaコマンドでComandLineJobRunnerから起動する他に、監視処理からJobOperatorで起動する方法があるようです。
以下はJavaコマンドでJobを実行する際のコマンドの例です。
java -jar {jar名} {batchのxmlファイル} {Job名} {パラメータ名=値}
set tmptime=%Time: =0%
java -jar test-batch.jar testJob.xml jobA file=testdata.csv datetime=%DATE:~-10,4%%DATE:~-5,2%%DATE:~-2%%tmptime:~0,2%%tmptime:~3,2%%tmptime:~6,2%
最後に
Spring Batchにある多彩な機能を網羅するのは大変ですね。
基本を押さえて開発することで、ぐんっと成長の幅も広がると思うので、ここで一度作っているシステムを見返してみるのも良いかもしれません。