[Java][Spring Boot] Spring BatchでTaskletを使ってみる。
はじめに
以前の記事で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が実行されませんでした。 課題として、別の形での確認方法を考えたいと思います。