Batch Scope & Job Parameter
Spring Batch์ ๊ฒฝ์ฐ ์ธ๋ถ, ๋ด๋ถ์์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์ ์ฌ๋ฌ Batch ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ ์ ์๊ฒ ์ง์ํ๊ณ ์๋๋ฐ ์ด๋ฅผ Job Parameter๋ผ ํ๋ค.
Job Parameter๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ํญ์ Spring Batch ์ ์ฉ Scope๋ฅผ ์ ์ธํด์ผํ๋๋ฐ ์ข
๋ฅ๋ ํฌ๊ฒ @StepScope์ @JobScope๊ฐ ์๋ค.
@Value("#{jobParameters[ํ๋ผ๋ฏธํฐ๋ช
]}")Job Parameter๋ Double, Long, Date, String ํ์
์ ์ฌ์ฉํ  ์ ์์ผ๋ฉฐ, LocalDate์ LocalDateTime์ ์ ๊ณตํ์ง ์์, ํ์
์ ๋ณํํด์ ์ฌ์ฉํด์ผํ๋ค.
Job Parameter ์ฌ์ฉ์ ๋ง์ด ์คํดํ๋ ๋ถ๋ถ์ด ์๋ค. Job Parameter๋ Scope Bean์ ์์ฑํ ๋๋ง ์ฌ์ฉ ๊ฐ๋ฅํ๋ค. ์ฆ, @StepScope, @JobScope Bean์ ์์ฑํ ๋๋ง Job Parameters๊ฐ ์์ฑ๋๋ค.
Bean Scope
Spring Bean์ ๊ธฐ๋ณธ Scope๋ singleton์ด์ง๋ง, @JobScope, @StepScope๋ฅผ ์ฌ์ฉํ๊ฒ๋๋ฉด Spring Batch๊ฐ ์ง์ ๋ Job/Step์ ์คํ ์์ ์ ํด๋น ์ปดํฌ๋ํธ๋ฅผ Spring Bean์ผ๋ก ์์ฑํ๋ค. ์ฆ, Bean์ ์์ฑ ์์ ์ ์ง์ ๋ Scope๊ฐ ์คํ๋๋ ์์ ์ผ๋ก ์ง์ฐ์ํฌ ์ ์๋ค.
JobScope, StepScope๋ Job/Step์ด ์คํ๋๊ณ ๋๋ ๋ ๊ฐ๊ฐ ์์ฑ/์ญ์ ๊ฐ ์ด๋ฃจ์ด์ง๋ค๊ณ ๋ณด๋ฉด๋๋ค.
์ด๋ ๊ฒ Bean ์์ฑ์์ ์ ์ง์ฐ์ํค๋ฉด ์ป๋ ์ฅ์ ์ ํฌ๊ฒ 2๊ฐ๊ฐ ์๋ค.
1. JobParameter์ Late Binding
๊ผญ application์ด ์คํ๋๋ ์์ ์ด ์๋๋๋ผ๋, Controller, Service์ ๊ฐ์ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ๋จ๊ณ์์ Job Parameter๋ฅผ ํ ๋น์ํฌ ์ ์๋ค.
2. ๋์ผํ ์ปดํฌ๋ํธ๋ฅผ ๋ณ๋ ฌ ํน์ ๋์์ ์ฌ์ฉํ ๋ ์ ์ฉ
์๋ฅผ ๋ค์ด, Step๋ด๋ถ์ Tasklet์ด ์๊ณ , ์ด Tasklet์ ๋ฉค๋ฒ ๋ณ์๋ฅผ ๋ณ๊ฒฝํ๋ ๋ก์ง์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณด์.
์ด ๊ฒฝ์ฐ @StepScope ์์ด Step์ ๋ณ๋ ฌ๋ก ์คํํ๊ฒ๋๋ฉด ์๋ก ๋ค๋ฅธ Step์์ ํ๋์ Tasklet์ ๋๊ณ  ๋ง๊ตฌ์ก์ด๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ค๊ณ  ํ ๊ฒ์ด๋ค. ํ์ง๋ง, @StepScope๋ก Scope๋ฅผ ๋ณ๊ฒฝํ๋ฉด ๊ฐ๊ฐ์ Step์์ ๋ณ๋์ Tasklet์ ์์ฑํ๊ณ  ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์๋ก์ ์ํ๋ฅผ ์นจ๋ฒํ  ์ผ์ด ์๋ค.
์ฌ์ฉ ์์ 
@JobScope
@JobScope๋ Step ์ ์ธ๋ฌธ์์ ์ฌ์ฉ๊ฐ๋ฅ
@Bean
public Job scopeJob() {
  	return jobBuilderFactory.get("scopeJob")
      			.start(scopeStep())
      			.build();
}
@Bean
@JobScope
public Step scopeStep(@Value("#{jobParameters[requestDate]}") String requestDate){
  
  	return stepBuilderFactory.get("scopeStep")
      				.tasklet((stepContribution, chunkContext) -> {
                    log.info(">>> Start step : {}", requestDate);
                    return RepeatStatus.FINISHED;
                }).build();
}@StepScope
@StepScope๋ Tasklet, ItemReader, ItemWriter, ItemProcessor ๋ฑ์์ ์ฌ์ฉ ๊ฐ๋ฅ
@Bean
public Step scopeStep2(){  
  	return stepBuilderFactory.get("scopeStep2")
      				.tasklet(scopeStepTasklet())
      				.build();
}
@Bean
@StepScope
public Tasklte scopeStepTasklet(@Value("#{jobParameters[requestDate]}") String requestDate){  
  	return (stepContribution, chunkContext) -> {
               log.info(">>> Start scopeStepTasklet : {}", requestDate);
               return RepeatStatus.FINISHED;
            };
}Class ๋ฉค๋ฒ ๋ณ์๋ก ํ ๋น๋ฐ๊ธฐ
@Bean
public Job simpleJob() {
  	return jobBuilderFactory.get("simpleJob")
      			.start(simpleStep())
      			.build();
}
// ์์ฑ์
private final SimpleJobTasklet tasklet;
public Step simpleStep(){
  	log.info("Start simpleStep");
  
  	return stepBuilderFactory.get("simpleStep")
      				.tasklet(tasklet1).build();
}/**
	* StepScope๋ก ์์ฑํ๊ธฐ๋๋ฌธ์ JobParameters๋ฅผ ๋ฐ์์ฌ ์ ์๋ค.
	*/
@Component
@StepScope
public class SimpleJobTasklet implements Tasklet{
  
  	// ํด๋์ค ๋ฉค๋ฒ ๋ณ์๋ก ํ ๋น
  	@Value("#{jobParameters[requestDate]}")
  	private String requestDate;
  
  	public SimpleJobTasklet(){ log.info("SimpleJobTasklet ์์ฑ");}
  
  	@Override
  	public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception{
      	log.info("SimpleJobTasklet execute");
      	log.info("requestDate : {}", requestDate);
      
      	return RepeatStatus.FINISHED;
    }
}Job Parameter vs ์์คํ
 ๋ณ์
JobParameter
@Bean
@StepScope
public FlatFileItemReader<Partner> reader(
        @Value("#{jobParameters[pathToFile]}") String pathToFile){
    FlatFileItemReader<Partner> itemReader = new FlatFileItemReader<Partner>();
    itemReader.setLineMapper(lineMapper());
    itemReader.setResource(new ClassPathResource(pathToFile));
    return itemReader;
}์์คํ
 ๋ณ์
์์คํ
 ๋ณ์๋ application.properties์ -D ์ต์
์ผ๋ก ์คํํ๋ ๋ณ์ ํฌํจ
@Bean
@ConfigurationProperties(prefix = "my.prefix")
protected class JobProperties {
    String pathToFile;
    ...getters/setters
}
@Autowired
private JobProperties jobProperties;
@Bean
public FlatFileItemReader<Partner> reader() {
    FlatFileItemReader<Partner> itemReader = new FlatFileItemReader<Partner>();
    itemReader.setLineMapper(lineMapper());
    String pathToFile = jobProperties.getPathToFile();
    itemReader.setResource(new ClassPathResource(pathToFile));
    return itemReader;
}1. ์์คํ  ๋ณ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ ๊ฒฝ์ฐ Spring Batch์ Job Parameter ๊ด๋ จ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ๋ชปํ๋ค.
Spring Batch๋ ๊ฐ์ JobParameter๋ก ๊ฐ์ Job์ ๋ ๋ฒ ์ํํ์ง ์๋๋ค. ํ์ง๋ง ์์คํ  ๋ณ์๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ ๊ฒฝ์ฐ์๋ ์ด ๊ธฐ๋ฅ์ด ์ ํ ๋์ํ์ง ์๊ฒ ๋๋ค. ๋ํ Spring Batch์์ ์๋์ผ๋ก ๊ด๋ฆฌํด์ฃผ๋ Parameter ๊ด๋ จ ๋ฉํ ํ ์ด๋ธ์ ์ ํ ๊ด๋ฆฌ๊ฐ ๋์ง ์๊ฒ ๋๋ค.
์ฆ, Job Parameter๋ฅผ ์ฌ์ฉํ์ง ๋ชปํ๋ ๊ฒ์ Late Binding์ ๋ชปํ๋ค๋ ์๋ฏธ์ด๋ค.
2. Command Line์ด ์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก Job์ ์คํํ๊ธฐ ์ด๋ ต๋ค.
์ฃผ์ ์ฌํญ
@Scope(
    value = "step",
    proxyMode = ScopedProxyMode.TARGET_CLASS
)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StepScope {
}@StepScope ๋ด๋ถ ์ฝ๋๋ฅผ ๋ณด๋ฉด @Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS) ๋ก ํ์ํ๋ ๊ฒ๊ณผ ๊ฐ๋ค. ์ด๋ proxyMode๋ก ์ธํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ  ์ ์๋ค.
์๋ฅผ ๋ค์ด @StepScope๋ฅผ ์ฌ์ฉํ๋๋ฐ, ํด๋น Bean์ return type์ด ์ธํฐํ์ด์ค์ธ ๊ฒฝ์ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ  ์ ์๋ค.
@Bean
@StepScope
public ItemReader<Person> reader(@Value("#{jobParameters[name]}") String name){
  	Map<String, Object> params = new HashMap<>();
  	params.put("name", name);
  
	  JpaPagingItemReader<Person> reader = new JpaPagingItemReader<>();
  	reader.setQueryString("select * from person where name = :name");
  	reader.setParameterValues(params);
  	reader.setEntityManagerFactory(entityManagerFactory);
  	reader.setPageSize(CHUNK_SIZE);
		return reader;
}o.s.b.c.l.AbstractListenerFactoryBean    : org.springframework.batch.item.ItemReader is an interface.  The implementing class will not be queried for annotation based listener configurations.  If using @StepScope on a @Bean method, be sure to return the implementing class so listner annotations can be used.๊ด๋ จ ๋ด์ฉ์ ์ ๋ฆฌํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
@Bean ๋ฉ์๋์์ @StepScope๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ listner ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ  ์ ์๋๋ก ๊ตฌํ ํด๋์ค๋ฅผ returnํด์ผํ๋ค. ์๋์ ๊ฐ์ด ๊ตฌํ ํด๋์ค๋ฅผ returnํ์ฌ ํด๋น ๋ฌธ์ ์ ์ ํด๊ฒฐํ  ์ ์๋ค.
@Bean
@StepScope
public JpaPagingItemReader<Person> reader(@Value("#{jobParameters[name]}") String name){
  	Map<String, Object> params = new HashMap<>();
  	params.put("name", name);
  
	  JpaPagingItemReader<Person> reader = new JpaPagingItemReader<>();
  	reader.setQueryString("select * from person where name = :name");
  	reader.setParameterValues(params);
  	reader.setEntityManagerFactory(entityManagerFactory);
  	reader.setPageSize(CHUNK_SIZE);
		return reader;
}์ฐธ๊ณ 
Last updated
Was this helpful?