본문 바로가기
Spring/Batch

[Spring Batch] 스프링 배치 핵심 컴포넌트와 Job/Step 구조

by coding_whale 2026. 5. 7.
반응형

복잡한 배치 시스템을 효율적으로 제어하기 위해서는 먼저 전체 구조를 꿰뚫는 시야가 필요하다. Spring Batch는 단순히 데이터를 옮기는 도구가 아니라, 수많은 컴포넌트가 유기적으로 엮여 대용량 데이터를 안전하게 처리하는 거대한 프레임워크다.

이번 포스팅에서는 스프링 배치의 근간이 되는 Job과 Step의 개념을 정의하고, 시스템의 전체 아키텍처를 '제공'과 '제어'의 관점에서 해부해 본다. 또한, 실제 프로젝트를 구성하는 두 가지 전략(Raw vs Boot)을 비교하며 첫 번째 배치 잡을 실행해 본다.

 

1. 배치의 근간: Job과 Step 이해하기

스프링 배치를 배우면서 가장 많이 듣게 될 핵심 용어는 JobStep이다. 이 두 개념은 배치 처리의 실행 단위와 논리적 계층 구조를 결정짓는 핵심 요소다.

🔍 Job: 배치 처리의 가장 큰 단위

Job은 하나의 완전한 배치 작업을 의미한다. 실무에서 접하는 '일일 매출 집계', '정기 결제' 등은 모두 하나의 Job으로 표현된다.

🔍 Step: Job을 구성하는 실행 단위

Step은 Job을 구성하는 개별 단계로, 하나의 Job은 하나 이상의 Step으로 구성된다. Job이 성공하기 위해서는 포함된 모든 Step이 순차적으로 정상 완료되어야 한다.

 

 

2. Spring Batch 시스템의 두 영역: 제공과 제어

스프링 배치는 배치를 만들기 위해 필요한 대부분의 뼈대(컴포넌트 및 실행 흐름)를 이미 제공한다. 개발자는 이 뼈대 위에 스프링 배치가 제공하는 컴포넌트들을 @Configuration을 통해 적절히 조합하고 비즈니스 로직을 주입하기만 하면 된다.

🛠️ 프레임워크가 제공하는 영역 (Framework Area)

  1. JobLauncher: Job을 실행하고 실행에 필요한 파라미터를 전달하는 배치 작업의 시작점이다.
  2. JobRepository: 배치 처리의 모든 메타데이터(시작/종료 시간, 상태, 결과 등)를 저장하고 관리하는 핵심 DB 저장소다.
  3. ExecutionContext: Job과 Step 실행 중의 상태 정보를 key-value 형태로 담는 객체다. 실패 후 재시작 시 상태 복원에 활용된다.
  4. 표준 구현체: JdbcCursorItemReader, JpaPagingItemReader, JdbcBatchItemWriter 등 검증된 데이터 처리 컴포넌트들을 제공한다.

🛠️ 개발자가 제어하는 영역 (Developer Area)

  1. Job/Step 구성: 각 Step의 실행 순서와 조건을 설정하고 스프링 빈(Bean)으로 등록한다.
  2. 세부 로직 지정: 표준 구현체를 쓰더라도 SQL 쿼리 조건이나 파일 포맷 매핑 방식은 직접 지정해야 한다.
  3. 단순 작업(Tasklet) 구현: 데이터 이동 외에 파일 복사, 디렉토리 정리, 알림 발송과 같은 커스텀 로직을 작성한다.
  4. ItemProcessor: 읽은 데이터를 가공하고 필터링하는 비즈니스 핵심 로직을 담당한다.

 

3. 프로젝트 구성: 두 가지  전략

흐름을 이해하기 위한 첫 번째 단계는 프로젝트 구축이다. 우리는 순수 스프링 배치 방식(Raw)과 스프링 부트(Boot) 기반 방식의 차이를 명확히 이해해야 한다.

전략 1: 순수 스프링 배치 방식

스프링 부트 없이 순수한 스프링 배치만을 사용하는 방식이다. 인프라 설정을 직접 경험하며 배치의 근간을 이해하기 좋다.

  • 설정 포인트: DefaultBatchConfiguration을 상속받아 DataSource와 PlatformTransactionManager를 수동으로 등록해야 한다.
  • 실행 방식: 명령줄 유틸리티인 CommandLineJobRunner를 메인 클래스로 활용한다.

 

전략 2: 스프링 부트 기반 방식

spring-boot-starter-batch를 활용하는 현대적인 방식이다. 복잡한 인프라 설정은 프레임워크가 자동 설정(Auto Configuration)으로 처리해 준다.

  • 설정 포인트: 스프링 부트가 핵심 인프라 빈들을 자동으로 구성하므로, 개발자는 비즈니스 로직 작성에만 집중할 수 있다.
  • 실행 방식: JobLauncherApplicationRunner가 프로퍼티에 지정된 Job을 찾아 자동으로 실행한다.

 

4. 코드 

이제 가상의 'System Termination' 시나리오를 통해 첫 번째 배치 Job을 실행해 본다. 이 예제는 데이터를 대량으로 다루는 '청크 지향' 방식 대신, 단일 작업을 처리하는 Tasklet 방식을 사용한다.

📝 시뮬레이션 시나리오

  1. enterWorldStep: 가상 세계에 입장한다.
  2. meetNPCStep: 관리자 NPC를 만나 미션을 확인한다.
  3. defeatProcessStep: 좀비 프로세스 5개를 순차적으로 처형한다. (RepeatStatus 활용)
  4. completeQuestStep: 보상을 확인하고 미션을 종료한다.

핵심 코드 분석 (전략적 침투 버전)

@Bean
public Job systemTerminationSimulationJob() {
    return new JobBuilder("systemTerminationSimulationJob", jobRepository)
            .start(enterWorldStep())      // 미션 시작
            .next(meetNPCStep())         // 다음 단계로
            .next(defeatProcessStep())   // 조건부 반복 단계
            .next(completeQuestStep())   // 최종 완료
            .build();
}

@Bean
public Step defeatProcessStep() {
    return new StepBuilder("defeatProcessStep", jobRepository)
            .tasklet((contribution, chunkContext) -> {
                int terminated = processesKilled.incrementAndGet();
                System.out.println("좀비 프로세스 처형 완료! (현재 " + terminated + "/5)");
                // 5개가 채워질 때까지 이 Step을 반복함
                return terminated < 5 ? RepeatStatus.CONTINUABLE : RepeatStatus.FINISHED;
            }, transactionManager)
            .build();
}
  • JobBuilder/StepBuilder: Job과 Step을 직관적으로 구성하기 위한 유틸리티 클래스다.
  • Tasklet: 데이터를 읽고 가공하고 쓰는 정형화된 패턴이 아닌, 단순 로직이나 제어 로직을 실행할 때 사용한다.
  • RepeatStatus: CONTINUABLE을 반환하면 해당 Step을 재호출하고, FINISHED를 반환하면 해당 단계를 마친다.

 

5. 마무리하며

이번 과정을 통해 우리는 스프링 배치가 제공하는 강력한 뼈대와 개발자가 직접 제어해야 할 비즈니스 영역을 명확히 구분해 보았다. 단순한 예제였지만, 이를 통해 Job과 Step이 어떻게 순차적으로 실행되는지, 그리고 스프링 부트가 얼마나 많은 복잡한 설정을 대신 처리해 주는지 체감할 수 있었다.

배치 잡을 실제로 '실행(Execute)' 시켜본다는 것은 단순히 코드를 돌리는 것을 넘어, 시스템을 자동화된 관리 체계 아래 두는 첫걸음이다. 이제 무기를 점검했으니, 다음 장부터는 본격적으로 대용량 데이터를 다루는 무기인 ItemReader, ItemProcessor, ItemWriter를 하나씩 공부할 것이다.

반응형