「Spring Batch 入門ガイド」を実用化する3
目的
「Spring Batch入門ガイド(バッチサービスの作成)」を基に、追加要件を組み込むことで、より実用的なバッチプログラムの作成方法を解説します。
背景
Step間で、データの引き渡しが必要になる場面がありました。
要件
背景を踏まえて、以下の要件を設定しました。
-
step1
のデータを引き渡す -
step2
を追加し、引き渡されたデータをログ出力する
これらの要件を満たすために、「Spring Batch入門ガイド」のサンプルプログラムを修正および追加します。
step1
のデータを引き渡す
1.
PersonItemWriter
クラスの作成
1.1 まず、BatchConfiguration
からライターをクラス分けし、ItemWriter
、StepExecutionListener
をインタフェースしたPersonItemWriter
クラスを作成します。
public class PersonItemWriter implements ItemWriter<Person>, StepExecutionListener {
private ListItemWriter<Person> writer = new ListItemWriter<>();
@Override
public void write(Chunk<? extends Person> chunk) throws Exception {
writer.write(chunk);
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
ExecutionContext context = stepExecution.getJobExecution().getExecutionContext();
List<? extends Person> person = (List<? extends Person>) writer.getWrittenItems();
context.put("listItem", person);
return stepExecution.getExitStatus();
}
}
ライターは、ListItemWriter
を使用して、List
に値を追加するように変更します。さらに、リスナーを追加し、afterStep
でJobExecutionContextに格納します。
Person
クラスのシリアライズ
1.2 Person
オブジェクトをJobExecutionContextに格納するには、シリアライズする必要がありますので、Serializable
をインタフェースします。
public record Person(String firstName, String lastName) implements Serializable {
}
step2
を追加し、引き渡されたデータをログ出力する
2.
Step2Tasklet
クラスの追加
2.1 Step2Tasklet
クラスで、JobExecutionContextに格納されたPerson
オブジェクトを取得し、ログ出力します。
public class Step2Tasklet implements Tasklet {
private static final Logger log = LoggerFactory.getLogger(Step2Tasklet.class);
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
ExecutionContext context = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext();
@SuppressWarnings("unchecked")
List<Person> listItem = (List<Person>) context.get("listItem");
listItem.forEach(person -> log.info("Found <{{}}> in the JobExecution.", person));
return RepeatStatus.FINISHED;
}
}
BatchConfiguration
の修正
2.2 writer
、importUserJob
、step1
メソッドの修正と、step2
メソッドの追加をします。
@Configuration
public class BatchConfiguration {
@Bean
public FlatFileItemReader<Person> reader() {
return new FlatFileItemReaderBuilder<Person>()
.name("personItemReader")
.resource(new ClassPathResource("sample-data.csv"))
.delimited()
.names("firstName", "lastName")
.targetType(Person.class)
.build();
}
@Bean
public PersonItemProcessor processor() {
return new PersonItemProcessor();
}
@Bean
public PersonItemWriter writer() {
return new PersonItemWriter();
}
@Bean
public Job importUserJob(JobRepository jobRepository,Step step1, Step step2, JobCompletionNotificationListener listener) {
return new JobBuilder("importUserJob", jobRepository)
.listener(listener)
.start(step1)
.next(step2)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, DataSourceTransactionManager transactionManager,
FlatFileItemReader<Person> reader, PersonItemProcessor processor, PersonItemWriter writer) {
return new StepBuilder("step1", jobRepository)
.<Person, Person> chunk(3, transactionManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
public Step step2(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step2", jobRepository)
.tasklet(new Step2Tasklet(), transactionManager)
.build();
}
}
以上で、要件を満たしました。
参考
「Spring Batch入門ガイド」のサンプルプログラはインメモリデータベースを使用しているため、簡単に内容を確認したい場合は、ログ出力になります。
JobCompletionNotificationListener
クラスでは、people
テーブルの内容をログ出力していますが、本修正によってpeople
テーブルへの挿入は行っていませんので、ログ出力されません。その代わりに、使用しているテーブル一覧をログ出力するように変更しました。
jdbcTemplate.queryForList(
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'PUBLIC'"
).forEach(result -> log.info("Record <{{}}>", result));
更新・追加ソースファイル
「Spring Batch入門ガイド」のサンプルプログラムに加えた、更新および追加のファイルは以下の通りです。
└── src
└── main
└── java
└── com.example.batchprocessing
├── BatchConfiguration.java(更新)
├── JobCompletionNotificationListener.java(更新)
├── Person.java(更新)
├── PersonItemWriter.java(追加)
└── Step2Tasklet.java(追加)
コード
Java17、Spring Batch 5.1.0、Spring Boot 3.2.0で、動作確認しています。ビルドツールは、Mavenを使用しています。
Discussion