5. Spring Batch Guide - Batch Scope & Job Parameter

JungHwan Oh·2025년 8월 16일

Spring Batch Guide

목록 보기
5/5

이번에는 Spring Batch Scope 에 대해서 알아보겠습니다. 알아볼 Scpoe 은 @StepScope 과 @JobScope 입니다. 또한 이것들과 연관이 있는 Job Parameter 에 대해서도 알아보겠습니다.

5.1 JobParameter 와 Scope

Spring Batch의 경우 외부 혹은 내부에서 파라미터를 받아 여러 Batch 컴포넌트에서 사용 할 수 있게 지원 하고 있는데요. 이 파라미터를 Job Parameter라고 합니다.

Job Parameter를 사용하기 위해선 항상 Spring Batch 전용 Scope를 선언해야 합니다. 그것들은 바로 @StepScope와 @JobScope 2가지가 있습니다. 사용법은 간단합니다. SpEL 로 선언해서 사용 할 수 있습니다.

@Value("#{jobParameters[Parameter Name]}")

주의 할 점
1. @StepScope/@JobScope 없이 @Value("#{jobParameters[...]}" )를 쓰면 null이 주입되거나 초기화 시점 오류가 납니다.
2. Batch 5.x에서는 JobBuilderFactory/StepBuilderFactory 대신 new JobBuilder(...), new StepBuilder(...) 를 사용하는 것이 표준입니다

JobScope

    @Bean
    public Job scopeJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        return new JobBuilder("scopeJob", jobRepository)
                .start(scopeStep1(jobRepository, transactionManager, null))
                .next(scopeStep2(jobRepository, transactionManager))
                .build();
    }
    
    @Bean
    @JobScope
    public Step scopeStep1(JobRepository jobRepository,
                           PlatformTransactionManager transactionManager,
                           @Value("#{jobParameters['requestDate']}") String requestDate) {
        return new StepBuilder("scopeStep1", jobRepository)
                .tasklet((contribution, chunkContext) -> {
                    log.info(">>>>> This is scopeStep1");
                    log.info(">>>>> requestDate = {}", requestDate);
                    return RepeatStatus.FINISHED;
                }, transactionManager)
                .build();
    }
    

StepScope

    @Bean
    public Step scopeStep2(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        return new StepBuilder("scopeStep2", jobRepository)
                .tasklet(scopeStep2Tasklet(null), transactionManager)
                .build();
    }

    @Bean
    @StepScope
    public Tasklet scopeStep2Tasklet(@Value("#{jobParameters['requestDate']}") String requestDate) {
        return (contribution, chunkContext) -> {
            log.info(">>>>> This is scopeStep2");
            log.info(">>>>> requestDate = {}", requestDate);
            return RepeatStatus.FINISHED;
        };
    }

@JobScope는 Step 선언문에서 사용 가능하고, @StepScope는 Tasklet이나 ItemReader, ItemWriter, ItemProcessor에서 사용할 수 있습니다.

이전에 Spring Batch 4.X 에서는 Job Parameter의 타입으로 사용할 수 있는 것은 Double, Long, Date, String 이 있습니다.

하지만, 이번에 Spring Batch 5.X 들어 서면서 LocalDate와 LocalDateTime을 Job Parameter의 타입으로 사용 할 수 있게 되었습니다. 다만 아쉬운건 타입을 직접 입력해야 한다는 것 입니다. 이건 잠시 뒤에 알아 보고

우선 예제 코드를 보시면 호출하는 쪽에서 null 를 할당하고 있습니다.
이는 Job Parameter의 할당이 어플리케이션 실행시에 하지 않기 때문에 가능한데요, 이게 어떤 무슨 말일까요? 자세히 보도록 하겠습니다.

5.2 @StepScope @JobScope

@StepScope, @JobScope Spring Batch 에서 제공하는 어노테이션으로 Bean Scope 을 지원 합니다. (Spring Bean 은 기본적으로 Sigleton)

그러나 아래 소스 처럼 Spring Batch 컴포넌트 (Tasklet, ItemReader, ItemWriter, ItemProcessor 등)에 @StepScope를 사용하게 되면

    @Bean
    @StepScope
    public Tasklet scopeStep2Tasklet(@Value("#{jobParameters['requestDate']}") String requestDate) {
        return (contribution, chunkContext) -> {
            log.info(">>>>> This is scopeStep2");
            log.info(">>>>> requestDate = {}", requestDate);
            return RepeatStatus.FINISHED;
        };
    }

Spring Batch 에서 Spring Container 를 통해서 Step의 실행시점에 해당 컴포넌트를 Spring Bean 으로 생성합니다. 같은 이치로 @JobScope는 Job 실행시점에 Bean이 생성합니다.
즉, Bean의 생성 시점을 지정된 Scope가 실행되는 시점으로 지연시킵니다

그렇다면, Spring Batch 왜 Bean 을 생성지점이 application 실행 시점이 아니라, Job 과 Step 실행 시점으로 지연 했을까요? 장점이 있을까요? 크게 2가지가 있습니다.

  1. JobParameter의 Late Binding이 가능합니다.
    Job Parameter가 StepExecution 또는 JobExecution 레벨에서 할당시킬 수 있습니다.
    꼭 Application이 실행되는 시점이 아니더라도 Controller나 Service와 같은 비지니스 로직 처리 단계에서 Job Parameter를 할당시킬 수 있습니다.

  2. 동일한 컴포넌트를 병렬 혹은 동시에 사용할때 유용합니다.
    Step 안에 Tasklet이 있고, 이 Tasklet은 멤버 변수와 이 멤버 변수를 변경하는 로직이 있다고 가정해봅시다.
    이 경우 @StepScope 없이 Step을 병렬로 실행시키게 되면 서로 다른 Step에서 하나의 Tasklet을 두고 마구잡이로 상태를 변경하게 될 것 입니다.
    하지만 @StepScope가 있다면 각각의 Step에서 별도의 Tasklet을 생성하고 관리하기 때문에 서로의 상태를 침범할 일이 없습니다.

5.3 JobParameter 의 오해

Job Parameters는 @Value를 통해서 사용이 가능합니다. 그에 따라서 다소 오해가 있을 수도 있습니다. 정확히 알아야 할 것은 Job Parameters는 Step이나, Tasklet, Reader 등 Batch 컴포넌트 Bean의 생성 시점 즉, Scope Bean을 생성할때만 사용이 가능합니다. 따라서 @StepScope, @JobScope Bean을 생성할때만 Job Parameters가 생성되기 때문에 사용할 수 있습니다.

아래 예시를 보면, 메소드를 통해서 Bean을 생성하지 않고, 클래스에서 직접 Bean 을 생성해보겠습니다.

Job과 Step의 코드에서 @Bean과 @Value("#{jobParameters[파라미터명]}")를 제거하고 SimpleJobTasklet을 생성자 DI로 받도록 합니다.

@Component
@Slf4j
@StepScope
public class SimpleTasklet implements Tasklet {

    @Value("#{jobParameters['requestDate']}")
    String requestDate;

    public SimpleTasklet() {
        log.info(">>>>> Create Tasklet");
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        log.info(">>>>> This is scopeStep1");
        log.info(">>>>> requestDate = {}", requestDate);
        return RepeatStatus.FINISHED;
    }
}
@Configuration
@Slf4j
@RequiredArgsConstructor
public class SimpleJobConfiguration {

    private final SimpleTasklet simpleTasklet;

    @Bean
    public Job simpleJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        return new JobBuilder("simpleTaskletJob", jobRepository)
                .start(simpleTaskletStep1(jobRepository, transactionManager))
                .build();
    }

    public Step simpleTaskletStep1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        log.info(">>>>> This is simpleStep1");
        return new StepBuilder("simpleTaskletStep1", jobRepository)
                .tasklet(simpleTasklet, transactionManager)
                .build();
    }
}

SimpleJobTasklet은 위와 같이 @Component와 @StepScope로 Scope가 Step인 Bean으로 생성합니다. 이 상태에서 @Value("#{jobParameters[파라미터명]}를 Tasklet의 변수로 할당합니다.

이렇게해서 메소드의 파라미터로 JobParameter를 할당받지 않고, 클래스의 멤버 변수로 JobParameter를 할당 받도록 해도 실행해보겠습니다.

보시는 것 처럼 정상적으로 JobParameter를 받아 사용할 수 있습니다.
이는 SimpleJobTasklet Bean이 @StepScope로 생성되었기 때문입니다.

이제는 소스코드에서 @StepScope 을 주석 처리하고 실행 해보겠습니다.

결과를 보면, 위와같이 'jobParameters' cannot be found 에러가 발생합니다.

이를 통해서 알 수 있는건 Bean을 메소드나 클래스 어느 것을 통해서 생성해도 무방하나 Bean의 Scope는 Step이나 Job이어야 한다는 것을 알 수 있습니다.

즉, JobParameters를 사용하기 위해선 꼭 @StepScope, @JobScope로 Bean을 생성해야한다는 것을 잊지마세요.

Reference
https://jojoldu.tistory.com/330
https://docs.spring.io/spring-batch/reference/step/late-binding.html

Source Code
https://github.com/trustonlyyou/batch-guide

profile
BACK_END DEVELOPER

0개의 댓글