要旨
簡単なSpringBatchを作成し、Webリクエストからバッチ起動する。
環境
- Java SE 8 (jdk-8u181)
- Spring Boot 2.1.0
詳細手順
プロジェクト作成
SpringBatchを使用するため、依存関係にspring-boot-starter-batch
を加える。
また、Job管理にDBを使用するため、適当なJDBCも加える。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
バッチ作成
基本的にこちらを参考に作成
バッチ実処理
@Service
として適当な処理クラスを作成
@Service
public class MyBatchService {
public void execute(Long id, String name, Date reqDate) throws InterruptedException {
// 適当なバッチ処理
Thread.sleep(5000);
}
}
バッチ設定
バッチ処理の肝。今回は簡単に1ステップ(タスクレット)のジョブを1つ作成する。
Javaのコンフィグレーションクラスで設定する。
@Configuration
@EnableBatchProcessing //(1)
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory; //(2)
@Autowired
private StepBuilderFactory stepBuilderFactory; //(2)
@Autowired
private MyBatchService service;
@Bean
public JobLauncher jobLauncher1(JobRepository jobRepository) { //(2),(3)
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 同時実行数は3.それ以上はキュー待ちになる.
taskExecutor.setCorePoolSize(3); //(4)
// java.lang.IllegalStateException: ThreadPoolTaskExecutor not initialized
taskExecutor.initialize(); //(5)
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.setTaskExecutor(taskExecutor);
return jobLauncher;
}
@Bean
public Job job(Step step1) { //(6)
return jobBuilderFactory.get("batchjob")
.incrementer(new RunIdIncrementer())
.start(step1)
.build();
}
@Bean
public Step step1(Tasklet tasklet1) { //(6)
return stepBuilderFactory.get("step1")
.tasklet(tasklet1)
.build();
}
@Bean
@StepScope //(7)
public Tasklet tasklet1( //(6)
@Value("#{jobParameters['id']}") Long id, //(8)
@Value("#{jobParameters['name']}") String name,
@Value("#{jobParameters['reqDate']}") Date reqDate
) {
//(9)
MethodInvokingTaskletAdapter tasklet = new MethodInvokingTaskletAdapter();
tasklet.setTargetObject(service);
tasklet.setTargetMethod("execute");
tasklet.setArguments(new Object[] {id, name, reqDate});
return tasklet;
}
}
(1) | SpringBatchの設定であることを示す@EnableBatchProcessing を@Configuration とともに付与する。 |
(2) | いくつかのBeanはデフォルトでコンテキストに含まれているのでAutowiredすることができる。 |
(3) | Job実行環境の設定。 |
(4) | CorePoolSizeで同時実行数(スレッドを立てる数)を設定する。これを超える場合はキュー待ちになり、スレッドが空き次第順次実行される。 |
(5) | initializeしておかないと"java.lang.IllegalStateException: ThreadPoolTaskExecutor not initialized"という例外が発生する。 |
(6) | Job, Step, Taskletの設定。 |
(7) | 実行時のパラメータを設定する場合は起動時にBeanを作成できないので@StepScope を付与しBean作成のタイミングを変更する。 |
(8) | jobParametersからオブジェクトを取り出す設定。 |
(9) | Invokeで実行する。 |
バッチ呼び出し
@Service
public class MyServletService {
@Autowired
private JobLauncher jobLauncher1;
@Autowired
private Job job;
public void request(Long id, String name) throws JobExecutionException {
// (10)
JobParameters params = new JobParametersBuilder()
.addLong("id", id)
.addString("name", name)
.addDate("reqDate", Calendar.getInstance().getTime())
.toJobParameters();
jobLauncher1.run(job, params);
}
}
(10) | Jobに渡すパラメータをJobParametersにまとめて渡す。 |
起動設定
application.ymlに設定を追加する。
application.yml
spring:
datasource: # (11)
url: jdbc:postgresql://localhost:5432/kurukuruz1
username: u-s-e-r
password: p-a-s-s
driver-class-name: org.postgresql.Driver
batch:
initialize-schema: always # (12)
job:
enabled: false # (13)
(11) | 使用するDBの接続情報を設定する。 |
(12) | SpringBatchが使用するテーブルのDDLを実行するための設定。デフォルトではembedded で、PostgreSQLを使用する場合はDDLが実行されないので、明示的に変更しておく。 |
(13) | デフォルトではtrue でSpring起動時にJobが実行されるが、起動時はJobParametersがないため起動時には実行できない。そのため明示的に変更しておく。 |
参考サイト
SpringBatch再入門 - 自分なりに使い方を整理してみた - Qiita
BLOG.IK.AM - 誤解しがちなThreadPoolTaskExecutorの設定
Spring Batch サンプルコード (Java/Gradle) - Qoosky
【Spring Batch】Jobの自動実行を行わない 指定したJob以外が自動で実行されてしまう時の制御法 - Qiita
コジオニルク - Spring Boot Batch で Hello World