0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring Batchとは

Last updated at Posted at 2024-10-15

概要

業務でSpring Batchが必要となったので勉強したことをまとめてみました
全て小文字に変換して表示するコードも書いてます

Spring Batchとは

Spring Frameworkを中心としたSpringプロジェクトの一つ。
バッチ処理を実現するために使用するフレームワーク。

バッチ処理:あらかじめ一連の処理手順を登録しておき、自動的に処理を行う方式のこと

Spring Batchでできること

  1. バッチ処理の定期的なコミット
  2. 並列、直列処理
  3. 実行タイミングの指定
  4. 処理結果による後続処理の分岐指定(リトライなど)

構成

image.png

構成 説明
JobLauncher Jobを起動するためのモジュール
Job バッチアプリケーションの一連の処理をまとめた1実行単位、Stepを呼び出す
Step Jobを構成する処理の単位、1つのJobに対して1~n個Stepを持たせることが可能
Tasklet 実際に実装される場所、①Chunkモデル ②Taskletモデル 2種の実装パターンがある
JobRepository 実行履歴を管理する機能、DB上のテーブルで管理され、リトライ時などに使用される

実装

種類

①Chunkモデル

一定件数のデータごとにまとめて、入力(ItemReader)・加工(ItemProcessor)・出力(ItemWriter)の順で処理する方式

②Taskletモデル

自由に処理を記述できる方式
SQLを1回発行するだけ、コマンドを発行するだけ、といった簡素なケースで使用
また複数のデータベースやファイルにアクセスしながら処理するような複雑で定型化しにくいケースでも使用

① Chunkモデル構成

image.png

インターフェース 説明
ItemReader データの入力を担うインターフェース、データベースやファイルからJavaオブジェクトへ変換する
ItemProcessor データの加工を担うインターフェース、入力チェックやビジネスロジックを実装する
ItemWriter データの出力を担うインターフェース、Javaオブジェクトからデータベースやファイルへ変換する

処理全体の流れ

image.png

やってみた

ゴール

{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
をInputとして、全て小文字に変換して表示する

実行構成

image.png

1. mainクラスの作成

@EnableBatchProcessingアノテーションを付与とあるが、Spring Boot v3.0 以降、このアノテーションは不要になったので削除

BatchSampleChunkApplication.java
package com.example.demo;

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

@SpringBootApplication
public class BatchSampleChunkApplication {

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

}

ItemProcessorの作成

SampleProcessor.java
package com.example.demo.chunk;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@StepScope
@Slf4j
public class SampleProcessor implements ItemProcessor<String, String> {

	Logger logger = LoggerFactory.getLogger(SampleProcessor.class);

	@Override
	public String process(String item) throws Exception {

		// 文字列の加工(小文字に変換)
		item = item.toLowerCase();
		logger.info("Processor:{}", item);
		return item;
	}
}

2. ItemReaderの作成

SampleReader.java
package com.example.demo.chunk;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@StepScope
@Slf4j
public class SampleReader implements ItemReader<String> {
	Logger logger = LoggerFactory.getLogger(SampleReader.class);

	// 配列
	private String[] input = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

	private int index = 0;

	@Override
	public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
		if (input.length > index) {
			// 配列の文字列を取得
			String message = input[index++];
			logger.info("Read:{}", message);

			return message;
		}
		return null;
	}
}

3. ItemWriterの作成

SampleWritter.java
package com.example.demo.chunk;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@StepScope
@Slf4j
public class SampleWritter implements ItemWriter<String> {

	Logger logger = LoggerFactory.getLogger(SampleProcessor.class);

	@Override
	public void write(Chunk<? extends String> chunk) throws Exception {
		logger.info("writer:{}", chunk);
		logger.info("=========");
	}
}

4. Batch設定クラスの作成

BatchConfig.java
package com.example.demo.config;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
public class BatchConfig {

	@Autowired
	private ItemReader<String> reader;
	@Autowired
	private ItemProcessor<String, String> processor;
	@Autowired
	private ItemWriter<String> writer;

	// Jobを生成
	@Bean
	public Job importUserJob(JobRepository jobRepository, Step chunkStep) {
		return new JobBuilder("importUserJob", jobRepository) // Builderの取得
				.incrementer(new RunIdIncrementer()) // IDのインクリメント
				.start(chunkStep) // 最初のStep
				.build(); // Jobの生成
	}

	@Bean
	public Step chunkStep(JobRepository jobRepository, DataSourceTransactionManager transactionManager) {
		return new StepBuilder("chunkStep", jobRepository) // Builderの取得
				.<String, String>chunk(3, transactionManager)// チャンクの設定
				.reader(reader) // readerセット
				.processor(processor) // processorセット
				.writer(writer) // writerセット
				.build(); // Stepの生成
	}

}

5. 実行

image.png

結果 データが読まれて、小文字に変換していることがわかる
2024-02-08T16:12:04.443+09:00  INFO 34882 --- [  restartedMain] c.e.demo.BatchSampleChunkApplication     : Started BatchSampleChunkApplication in 1.862 seconds (process running for 7.53)
2024-02-08T16:12:04.446+09:00  INFO 34882 --- [  restartedMain] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2024-02-08T16:12:04.496+09:00  INFO 34882 --- [  restartedMain] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=importUserJob]] launched with the following parameters: [{'run.id':'{value=1, type=class java.lang.Long, identifying=true}'}]
2024-02-08T16:12:04.517+09:00  INFO 34882 --- [  restartedMain] o.s.batch.core.job.SimpleStepHandler     : Executing step: [chunkStep]
2024-02-08T16:12:04.535+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Sunday
2024-02-08T16:12:04.537+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Monday
2024-02-08T16:12:04.537+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Tuesday
2024-02-08T16:12:04.538+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:sunday
2024-02-08T16:12:04.538+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:monday
2024-02-08T16:12:04.538+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:tuesday
2024-02-08T16:12:04.538+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : writer:[items=[sunday, monday, tuesday], skips=[]]
2024-02-08T16:12:04.540+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : =========
2024-02-08T16:12:04.543+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Wednesday
2024-02-08T16:12:04.543+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Thursday
2024-02-08T16:12:04.543+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Friday
2024-02-08T16:12:04.543+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:wednesday
2024-02-08T16:12:04.543+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:thursday
2024-02-08T16:12:04.544+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:friday
2024-02-08T16:12:04.544+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : writer:[items=[wednesday, thursday, friday], skips=[]]
2024-02-08T16:12:04.544+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : =========
2024-02-08T16:12:04.545+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleReader      : Read:Saturday
2024-02-08T16:12:04.545+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : Processor:saturday
2024-02-08T16:12:04.545+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : writer:[items=[saturday], skips=[]]
2024-02-08T16:12:04.546+09:00  INFO 34882 --- [  restartedMain] com.example.demo.chunk.SampleProcessor   : =========
2024-02-08T16:12:04.549+09:00  INFO 34882 --- [  restartedMain] o.s.batch.core.step.AbstractStep         : Step: [chunkStep] executed in 31ms

参考資料

Spring Batchのアーキテクチャ
Spring Batch入門
[公式ドキュメント] Creating a Batch Service
勉強になったYoutube
[公式ドキュメント] クラス JobBuilderFactory

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?