Spring Batch에서 단순히 로직을 짜는 것만큼이나 중요한 것이 바로 "외부에서 값을 어떻게 주입받고, 어떻게 관리할 것인가?" 입니다. 이 메커니즘을 제대로 이해하지 못하면, 매번 코드를 수정해서 배포해야 하는 끔찍한 상황이 벌어집니다.
오늘은 배치의 입력값을 다루는 JobParameters와, 배치의 생명주기를 관리하는 JobScope/StepScope에 대해 완벽하게 정리해 봅니다.
오늘은 배치의 입력값을 다루는 JobParameters와, 배치의 생명주기를 관리하는 JobScope/StepScope에 대해 완벽하게 정리해 봅시다.
1. JobParameters: 배치의 입력값
JobParameters는 배치 작업 실행 시 외부에서 주입하는 파라미터입니다. 단순한 Java Main Arguments나 -D 옵션과는 차원이 다릅니다.
- 역할:
- 동적 제어: 날짜, 파일 경로 등 실행 시점마다 변하는 값을 주입.
- Job Instance 식별: (중요 ⭐) **"같은 Job이라도 파라미터가 다르면 다른 실행이다"**라고 인식하게 해주는 식별자 역할.
✅ 1-1. 커맨드라인으로 전달하기 (기본)
실무에서는 주로 젠킨스(Jenkins)나 에어플로우(Airflow) 같은 스케줄러에서 커맨드라인으로 파라미터를 던집니다.
표기법: 파라미터명=값,타입,식별여부
# 예시: 2025년 12월 15일자 데이터를 처리하라
java -jar my-batch.jar --spring.batch.job.name=dailyJob targetDate=2024-12-15,java.time.LocalDate
- targetDate: 파라미터 키
- 2024-01-01: 파라미터 값
- java.time.LocalDate: 타입 (생략 시 String)
✅ 1-2. 코드로 주입받기 (@Value)
주입받은 파라미터는 SpEL(Spring Expression Language)을 사용하여 간편하게 꺼내 쓸 수 있습니다. 단, 반드시 @StepScope나 @JobScope가 필요합니다. (이유는 뒤에서 설명!)
@Bean
@StepScope // 필수! 이게 없으면 실행 시점에 값을 못 받아옴
public Tasklet dailyTasklet(
@Value("#{jobParameters['targetDate']}") LocalDate targetDate,
@Value("#{jobParameters['retryCount']}") Integer retryCount
) {
return (contribution, chunkContext) -> {
log.info("처리 대상 날짜: {}", targetDate);
log.info("재시도 횟수: {}", retryCount);
return RepeatStatus.FINISHED;
};
}
✅ 1-3. 쉼표(,)가 포함된 파라미터 (JSON 표기법)
targets=서울,부산 처럼 값 안에 쉼표가 들어가면 파싱 에러가 납니다. 이럴 땐 JSON 방식을 쓰면 깔끔합니다.
targets='{"value": "서울,부산", "type": "java.lang.String"}'
(Spring Batch 5부터 지원하며, JsonJobParametersConverter 설정이 필요할 수 있습니다.)
2. JobScope & StepScope: 배치의 특별한 생명주기
Spring의 기본 빈 스코프는 Singleton(앱 뜰 때 생성)입니다. 하지만 배치에서는 "Job이 실행될 때" 혹은 "Step이 실행될 때" 빈이 만들어져야만 하는 경우가 있습니다.
바로 JobParameters를 늦게(Late Binding) 받기 위해서입니다.
✅ 왜 필요한가요?
- Late Binding (지연 할당): 앱 구동 시점에는 targetDate가 뭔지 모릅니다. Job이 실제로 실행되는 순간에 파라미터를 받아와야 하므로, 빈 생성 시점을 뒤로 미루는 것입니다.
- Thread Safety (동시성 보장): 동일한 Job이 동시에 여러 번 실행될 때, 각 실행(Thread)마다 서로 다른 Step/Tasklet 인스턴스를 생성해 줍니다. (서로 간섭 X)
✅ 사용 범위 및 주의사항
- @JobScope: Job 실행 시 생성 ~ 종료 시 소멸. (Step 빈에 사용)
- @StepScope: Step 실행 시 생성 ~ 종료 시 소멸. (Tasklet, Reader, Writer, Processor 빈에 사용)
[주의] Step 빈에는 @StepScope를 쓰지 마세요!
// 잘못된 예: Step에 @StepScope를 걸면 안 됨
@Bean
@StepScope
public Step myStep() { ... }
// 올바른 예: Tasklet이나 Reader 같은 하위 컴포넌트에 거세요
@Bean
public Step myStep() {
return new StepBuilder(...)
.tasklet(myTasklet(), transactionManager)
.build();
}
@Bean
@StepScope // 여기에 걸어야 함!
public Tasklet myTasklet(...) { ... }
(Step은 프레임워크가 메타데이터 관리를 위해 미리 접근해야 하므로, StepScope를 걸면 실행 시점에 꼬일 수 있습니다.)
3. ExecutionContext: 배치의 기억 저장소 🧠
JobParameters가 "시작할 때 받은 명령서"라면, ExecutionContext는 "작업 도중 적어두는 메모장"입니다.
- 용도:
- Step 간 데이터 공유 (Step A 결과 → Step B 입력)
- 실패 후 재시작 시 상태 복원: (예: "100번째 줄까지 읽었음" 저장해두면, 재시작 시 101번째부터 수행)
// Step 1: 메모장에 데이터 저장
chunkContext.getStepContext().getStepExecution().getJobExecution()
.getExecutionContext().put("myKey", "중요한 데이터");
// Step 2: 메모장에서 데이터 꺼내기 (@Value 활용)
@Value("#{jobExecutionContext['myKey']}") String myData

@StepScope를 Step 빈에 붙이지 말라
| 개념 | 역할 | 특징 |
| JobParameters | 배치의 입력값 (Read-Only) | 잡 인스턴스를 식별하는 기준이 됨 |
| JobScope / StepScope | 빈의 생성 시점 지연 | JobParameters를 주입받기 위해 필수 |
| ExecutionContext | 배치의 상태 저장소 (R/W) | 재시작 시 복구 지원, Step 간 데이터 공유 |
'SpringBoot' 카테고리의 다른 글
| 좋아요 구현, Exclusive Lock에 대해서 알아보자. (0) | 2026.04.22 |
|---|---|
| [Spring Batch] Tasklet vs Chunk 간단 정리 (0) | 2025.12.15 |
| Kafka를 이용해서 인기글 서비스를 어떻게 구현할 수 있을까? (0) | 2025.08.20 |
| 분산 이벤트 스트리밍 플랫폼, Kafka 아는척해보기 (3) | 2025.08.17 |
| Swagger를 사용해서 쉽게 api명세서를 만들어보자! (2) | 2024.12.01 |