[SpringBoot] Spring Batch (2) - 설명 및 구현 예시

2024. 10. 7. 23:29Lang/JAVA


Spring Batch

Batch를 처리하기 위해 Java 기반의 다양한 도구가 존재하지만 대부분 Spring Batch를 사용하는 이유는 아래와 같다

 

1. 대용량 데이터 처리에 적합

- Spring Batch는 데이터를 청크 단위로 나눠 처리 하기 때문에 메모리 사용을 최소화한다.

- 예외상황 발생시 체크 포인트에서부터 다시 실행할 수 있도록 지원한다.

 

2. 복잡한 배치 처리 시나리오 지원

- 여러개의 Step을 조합하여 순차적 혹은 병렬적으로 실행 할 수 있으며 작업흐름을 제어하는 다양한 기능을 제공한다.

- 조건부 흐름을 통해 특정 조건에 따라 다음 스텝이 어떻게 실행될지 정의 가능하다

- Retry, Skip, 재시작 등 복구 전략도 쉽게 설정 할 수 있다.

 

3. 스케줄링 기능과의 연동

- Spring Batch 자체에는 스케줄링 기능이 내장되어 있지 않지만, Spring Scheduling, Quartz와 같은 스케줄러와 쉽게 연동하여 정기적인 배치 작업을 실행할 수 있다.

 



주요 개념

1. Job

- 배치 처리의 단위 작업

- ex) 뉴스 크롤링을 한다면 그 작업 자체가 하나의 Job

 

2. Step

- Job 내부의 세부 단계

- 데이터를 읽고 처리하며 저장하는 과정을 나눔

- ex) 뉴스 데이터를 읽는 Step, 데이터를 처리하는 Step 등

 

3. Reader

- 데이터를 읽어오는 역할

- ex) 뉴스 웹사이트에서 데이터를 읽어오는 작업

 

4. Processor:

- 데이터를 처리하는 역할

- ex) 읽어온 뉴스 데이터를 가공하거나 필터링하는 작업.

 

5. Writer

- 데이터를 저장하는 역할

- 처리된 데이터를 데이터베이스에 저장하거나 파일에 기록하는 작업

 



예시 코드

@Configuration
@EnableBatchProcessing  // 배치 작업을 설정하고 사용할 수 있도록 해주는 어노테이션
                        // JobRepository, JobLauncher, JobRegistry 등의 배치 관련 빈들을 자동으로 구성
public class BatchConfig {
    
    @Bean  // 메소드를 통해 생성된 객체를 Spring 컨테이너에서 관리하기 위해
           // Spring은 @Configuration이 붙은 클래스에서 @Bean 메소드가 있으면, 해당 메소드가 리턴하는 객체를 관리한다.
           // 이렇게 Spring에서 관리되는 객체는 의존성 주입(Dependency Injection)할 수 있다. 
           // 여기서 newsCrawlJob과 newsCrawlStep은 빈으로 등록되어, 나중에 다른 부분에서 사용될 수 있다.
    public Job newsCrawlJob(JobBuilderFactory jobBuilderFactory, Step newsCrawlStep) {
        return jobBuilderFactory.get("newsCrawlJob") 
                .incrementer(new RunIdIncrementer())  // 매번 다른 ID로 Job을 실행할 수 있도록 하는 클래스다. 
                                                      // Job이 여러 번 실행될 때 각 실행마다 고유한 ID를 부여해서 중복 실행을 피한다.
                .start(newsCrawlStep)  // Job의 첫 번째 Step을 설정한다. Job은 여러 Step으로 구성될 수 있는데, 
                                       // 여기서는 newsCrawlStep이라는 Step으로 시작한다.
                .build();  // Job 객체를 생성하여 반환한다.
    }


    @Bean
    public Step newsCrawlStep(StepBuilderFactory stepBuilderFactory, ItemReader<String> reader, 
                              ItemProcessor<String, String> processor, ItemWriter<String> writer) {
        return stepBuilderFactory.get("newsCrawlStep")
                .<String, String>chunk(10)  // 한 번에 처리할 데이터의 단위(청크)를 설정 
                .reader(reader)  // ItemReader : 데이터를 읽는 역할. 여기서는 String 타입 데이터를 읽어온다.
                .processor(processor)  // ItemProcessor : 데이터를 가공하는 역할. 읽어온 데이터를 변환하거나 필터링할 때 사용한다.
                .writer(writer)  // ItemWriter : 처리된 데이터를 저장하는 역할. 예를 들어, 파일에 저장하거나 DB에 저장한다.
                .build();  // Step 객체를 생성하여 반환한다.
    }


    @Scheduled(cron = "0 0 0 * * *")  // cron 표현식 => (초, 분, 시, 일, 월, 요일) 순서
    public void perform() {
        JobParameters params = new JobParametersBuilder()  // JobParameters는 Job을 실행할 때 추가적인 파라미터를 전달할 때 사용
                .addString("JobID", String.valueOf(System.currentTimeMillis()))  // 현재 시간을 이용해 고유한 Job ID 생성.
                .toJobParameters();
        jobLauncher.run(newsCrawlJob, params);  // JobLauncher는 Job을 실행
    }
    
}