[Java][Spring Boot] Spring BatchでTaskletを使ってみる。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

以前の記事でchunk(チャンク)を使ってバッチ処理の例をあげましたが、今回はtasklet(タスクレット)を使用したバッチ処理を使ってみました。
chunkでは、Reader → Compressor → WriterというETL処理を行いましたが、taskletはそこまで必要ない場合に使えるのだと思います。

環境

Mac OSX 10.10.5 Yosemite
Java 1.8.0_91
Spring Boot 1.3.7
PostgreSQL 9.5.1
Eclipse Mars 2

コード

起動クラス

package com.tasklet.batch;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BatchTaskletApplication {

	public static void main(String[] args) {
		SpringApplication.run(BatchTaskletApplication.class, args);
	}
}

BatchTasklet

package com.tasklet.batch;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing
public class BatchTasklet {

	@Autowired private Tasklet1 tasklet1;
	@Autowired private Tasklet2 tasklet2;
	@Autowired private JobBuilderFactory jobBuilderFactory;
	@Autowired private StepBuilderFactory stepBuilderFactory;
	
	@Bean
	public Step step1() {
		return stepBuilderFactory.get("step1")
				.tasklet(tasklet1)
				.build();
	}
	
	@Bean
	public Step step2() {
		return stepBuilderFactory.get("step2")
				.tasklet(tasklet2)
				.build();
	}

	@Bean
	public Job job(Step step1, Step step2) throws Exception {
		return jobBuilderFactory.get("job")
				.incrementer(new RunIdIncrementer())
				.listener(listener())
				.start(step1)
				.next(step2)
				.build();
	}

	@Bean
	public JobExecutionListener listener() {
		return new JobListener();
	}

}

ステップとジョブでバッチ処理を行うクラス。

25行目と32行目でタスクレットを使用するだけで、Reader、Processer、Writerは有りません。シンプルですね。
ステップではStepBuilderFactoryを、ジョブではJobBuilderFactoryを使用しています。

40行目、ジョブの開始と終了を知らせるリスナー。
46〜49行目、リスナーのBeanを作成しています。

41行目、チャンクの場合はflow(step1)としていましたが、タスクレットではstart(step2)を使用。

Tasklet1

package com.tasklet.batch;

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class Tasklet1 implements Tasklet {
	
	@Override
	public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
		System.out.println("tasklet1!!");
		return RepeatStatus.FINISHED;
	}

}

Tasklet2

package com.tasklet.batch;

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class Tasklet2 implements Tasklet {

	@Override
	public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
		System.out.println("tasklet2!!");
		return RepeatStatus.FINISHED;
	}

}

ステップに登録するタスクレットを準備。
Tasklet1と2は標準出力する文字が違うだけです。

13行目、タスクレットインターフェースを実装。

15〜19行目、タスクレットインターフェースのメソッドexecute。
ジョブ/ステップで呼ばれると実行され、戻り値に設定したRepeasStatus.FINISHEDかエラーを投げることで終了します。

JobListener

package com.tasklet.batch.listener;

import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
 
public class JobListener extends JobExecutionListenerSupport {
 
  @Override
  public void beforeJob(JobExecution jobExecution) {
    super.beforeJob(jobExecution);
    System.out.println("ジョブ開始");
  } 
 
  @Override
  public void afterJob(JobExecution jobExecution) {
    super.afterJob(jobExecution);
    System.out.println("ジョブ終了");
  }
 
}

ジョブの開始と終了を知らせてくれます。JobExecutionListenerSupportを実装するだけ。

実行

step1、step2、jobそれぞれのget("名称")で設定した名称が表示されます。

2016-08-15 15:31:47.803  INFO 90716 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=job]] launched with the following parameters: [{run.id=6}]
2016-08-15 15:31:47.828  INFO 90716 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
tasklet1!!
2016-08-15 15:31:47.876  INFO 90716 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step2]
tasklet2!!
2016-08-15 15:31:47.897  INFO 90716 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=job]] completed with the following parameters: [{run.id=6}] and the following status: [COMPLETED]

さいごに

チャンクと同じくタスクレットもステップ毎にトランザクションでラップされている様なので、その確認を行おうとしたのですが、上記の流れと同じくstep1を成功させ、次のstep2でエラーを投げるとstep1が実行されませんでした。
課題として、別の形での確認方法を考えたいと思います。