Spring/Batch

[Batch] Spring Batch 따라하기 | Creating a Batch Service

Kyle H 2023. 5. 30. 02:16

담당 시스템 재구축 프로젝트를 하면서, 

기존 레거시 시스템을 Spring Batch로 전환하게 되었습니다. 

자체 개발로 진행되지 않은 프로젝트 특성상.. 입맛에 맞지 않는 부분이 참 많습니다.

 

일단 Spring Batch에 대해 scratch부터 이해하고자, Spring 공식 가이드부터 따라하며 정리해보고자 합니다.

 

https://spring.io/guides/gs/batch-processing/#scratch

 

Getting Started | Creating a Batch Service

A common paradigm in batch processing is to ingest data, transform it, and then pipe it out somewhere else. Here, you need to write a simple transformer that converts the names to uppercase. The following listing (from src/main/java/com/example/batchproces

spring.io

 

먼저 프로젝트 생성부터 

Git fork 하는 방법도 있지만, 그냥 spring initializr를 사용하겠습니다.

 

pre-initialized project를 누르면 미리 설정된 정보를 가져옵니다. 

참고로 해당 예제는 Java 17 버전을 기본으로 하고 있습니다.

 

Generate 후 원하는 폴더에 압축 해제

IntelliJ에서 File -> Open -> build.gradle 선택 -> Open as Project 선택

 

Gradle의 load 작업이 완료되면, main 메서드를 실행시켜 이상이 없는지 확인합니다.

 

위에 나와있는대로 sameple 데이터와 sql 스크립트를 작성해서 넣어줍니다.

성과 이름, 그리고 id를 컬럼으로 갖고 있습니다.

sample data는 성과 이름을 나타내는 것 같네요.

한번 ^R을 눌러 정상 실행되는지 확인합니다.

 

이제 비즈니스 클래스를 작성합니다.

성과 이름을 상태로 가지고, getter setter를 가지는 단순한 클래스입니다.

A common paradigm in batch processing is to ingest data, transform it, and then pipe it out somewhere else.

batch의 핵심 개념을 나타냅니다. 데이터를 퍼올리고, 가공하고, 어딘가로 넘기는 것. 

그중에 가공하는 것에 해당하는 Processor 부분입니다. 

이런식으로 ItemProcessor를 상속받아 새로운 Processor를 만들면, 이후에 Step을 설정할때 작업 내역을 쉽게 만들 수 있습니다.

 

퍼올리고(Reader) -> 가공하고(Processor) -> 넘겨주고(Writer)

Processor는 Reader와 Writer의 중간다리 역할을 하기 때문에, 데이터 타입은 input과 output에 맞춰 변경될 수 있습니다.

 

스프링 배치는 다양한 유틸리티 클래스를 제공하여, 사용자가 비즈니스 로직 작성에 집중할 수 있게 해준다고 되어있습니다.

Job을 설정하기 위해선 먼저 @Configuration java class를 먼저 작성해야 합니다.

이 예제는 메모리 기반의 db를 사용하기 때문에, 작업이 완료되면 그 결과가 날라갑니다.

 

reader()는 sample-data.csv에서 데이터를 읽어와 Person 객체로 만들어 줍니다. 

processor()는 아까 위에서 만든 PersonItemProcessor 이고,

wirter(DataSource)는 sql을 통해 Person 객체를 Insert합니다. DataSource는 @EnableBatchProcessing에서 생성된 dataSource를 자동으로 복사해서 가져온다고 되어있네요.

Job은 Step으로 이루어져 있고, 각 Step은 reader, processor, writer을 가질 수 있습니다.

Job은 데이터베이스를 사용하여 실행 상태를 유지하기 때문에 incrementer가 필요하다고 되어있습니다. Job은 동일한 Job 파라미터로 여러번 실행 요청이 오는 경우, 설정에 따라 실행을 막을 수 있습니다. 이때, 동일한 Job 파라미터로도 Job을 구분할 수 있는게 이 id 값이라고 보면 됩니다.

chunk는 얼마나 많은 데이터를 한번에 쓸지 결정합니다. 이 예제에서는 한번에 10 records를 작성한다고 되어있네요.

chunk 앞에 <Person, Person>으로 되어있는 부분은 Reader와 Writer에서 각각 보여주는 데이터 타입과 동일합니다.

 

Job에 정의되어 있는 JobCompletionNotificationListener는 다음 과정에서 작성합니다.

JobExecutionListener는 다음 두 개의 default 메서드를 가지고 있습니다.

현재 원하는 내용은 Job이 완료되면, 데이터베이스에 쿼리를 날려 people 테이블을 조회하는 것이므로 afterJob을 오버라이드 해줍니다.

 

batch 프로세싱은 웹 애플리케이션 내에도 포함될 수 있지만, 이 예제에선 간단하게 단일 JAR 파일로 실행을 확인합니다.

@SpringBootApplication 어노테이션의 효능에 대해서도 얘기하고 있습니다.

(@Configuration class의 등록, @EnableAutoConfiguration의 기능, @CoponentScan 기능)

해당 프로젝트는 순수한 Java 애플리케이션이며, System.exit()와 SpringApplication.exit()는 job의 완료와 함께 JVM이 exit 되는 것을 보장한다고 되어있습니다.

main 메서드를 ide에서 직접 실행해도 동작하는 것을 확인 할 수 있지만, JAR 파일을 만들어 실행하는 것도 진행해 보겠습니다.

gradlew build

작업 결과는 bulid/libs 폴더에 생깁니다.

java -jar batch-processing-0.0.1-SNAPSHOT.jar

sample-data.csv는 280줄로 늘리고

JobCompletionNotificationListener 마지막에 아래 코드를 추가했습니다.

Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM people", Integer.class);
log.info("result count = {}", count);

result count = 280 으로 잘 나오는 것을 볼 수 있습니다.