티스토리 뷰

Spring Batch에서 실행할때 넘겨주는 Parameter 값을 받아서 동적으로 처리를 하고 싶은 경우가 있다. 

 

spring batch jobParameters

Springboot Batch에서는 이렇게 Program Arguments를 이용해 jobParameters를 전달한다. 바로 이 값을 어떻게 Batch 코드에서 받을수 있을까에 대한 이야기를 해보려 한다. 

 

jobParameters도 기본적으로 값을 받을때 @Value("#{jobParameters[testKey]}") 이런 형식으로 값을 받아야한다. 그냥 코드에 딸랑 저것만 넣으면 안된다. 이걸 사용할 수 있게 해주는것이 바로 @StepScope, @JobScope이다. 이것의 뜻은 Step 실행시점에 bean이 생성이 되는것, 혹은 Job 실행시점에 bean이 생성이 되는것이다. 지난번 yaml 파일의 값을 가지고 오면서 삽질을 한번 한 경험이 있어서 그런지 왜 이런것들을 써야 하는지 이해를 할수 있었다. 

간단하게 정리하면 배치의 구성요소중

 

Tasklet, Reader, Processor, Writer 를 사용할때 jobParameters를 가져오고 싶으면 각 메소드 위에 @StepScope를 붙여주고 한단계 위인 Step에서 jobParameters를 가져오고 싶으면 Step 정의 메소드 위에 @JobScope를 붙여준다. 

 

Chunk(Reader, Processor, Writer), Tasklet - @StepScope

reader 예제

@StepScope
@Bean
public FlatFileItemReader<Employee> testReader(@Value("#{jobParameters[testKey]}") String testKey) {
        
    log.info("############################" + testKey);
        
    return new FlatFileItemReaderBuilder<Employee>()
        .name("flatFileItemReader")
        .resource(new ClassPathResource("us-500.csv"))
        .delimited()
        .names(new String[]{"first_name", "last_name", "company_name", "address", "city", "county", "state", "zip", "phone1", "phone2", "email", "web"})
        .fieldSetMapper(new BeanWrapperFieldSetMapper<Employee>() {{
            setTargetType(Employee.class);
        }})
        .build();
}

@Bean
public Step sampleChunkStep(SampleStepListener stepListener, JdbcBatchItemWriter<Employee> testWriter) {
    return stepBuilderFactory.get("sampleChunkStep")
        .listener(stepListener)
        .<Employee, Employee> chunk(10)
        .reader(testReader(null))
        .processor(testProcessor())
        .writer(testWriter)
        .build();
}

@StepScope를 붙인 부분과 testReader 메소드 argument로 jobParameters 받는 부분, 그리고 step에서 reader를 호출할때 null 값을 넣어서 보내주는 부분정도 유심히 보면 될듯 싶다. 

 

 

tasklet 예제

@Bean
public Step sampleTaskletStep(SampleStepListener stepListener) {
    return stepBuilderFactory.get("sampleTaskletStep")
            .tasklet(sampleTasklet1(null))
        .build();
}

@Bean
@StepScope
public Tasklet sampleTasklet1(@Value("#{jobParameters[testKey]}") String testKey) {
    return (contribution, chunkContext) -> {
        log.info("############################" + testKey);
        return RepeatStatus.FINISHED;
    };
}

앞서 설명한 reader와 같은 레벨이니 거의 동일하게 사용한다고 보면 된다. testKey에 대한 값을 잘 가져온다.

 

 

Step - @JobScope

tasklet 예제

@Bean
public Job sampleTaskletJob() {
    return jobBuilderFactory.get("sampleTaskletJob")
        .incrementer(new RunIdIncrementer())
        .start(sampleTaskletStep(null))
        .build();
}

@Bean
@JobScope
public Step sampleTaskletStep(@Value("#{jobParameters[testKey]}") String testKey) {
    log.info("############################" + testKey);
    return stepBuilderFactory.get("sampleTaskletStep")
            .tasklet(sampleTasklet1())
        .build();
}

@StepScope와 사용법은 거의 동일하고 한 depth 위로 올라간 개념이라고 보면 된다.

단 Step을 실행시킬때 start()로 하지 않고 flow()로 하는건 이 방법이 통하지 않는다. flow를 사용하고 싶을때는 Flow 객체를 생성해서 사용하는 방법을 이용해보자. 

 

끝!

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31