아래 강의를 보고 정리한 내용입니다. 

[우아한테크세미나] 190926 우아한스프링배치 by 우아한형제들 이동욱님  https://youtu.be/_nkJkWVH-mo

 

  • JobParameter
    • Spring Batch는 외부에서 파라미터를 주입받아 Batch 컴포넌트에서 사용 할 수 있다. 
    • 사용법 : @Value("#{jobParameters[파라미터명]}") 타입 이름
  • @JobScope
    • Step에서 사용할 수 있고, Job이 실행되는 시점에 Bean이 생성된다.
    • 사용 예
      • @JobScope라고 선언해줘야 호출한 곳에서 넘겨진 파라미터를 받을 수 있다.
      • 컴파일 에러 방지를 위해 우선은 null값을 넘겨준다.
@Bean
public Job scopeJob() {
	return jobBuilderFactory.get("scopeJob")
    			.start(scopeStep1(null))
                            .next(scopeStep2())
                            .build();
}

@Bean
@JobScope
public Step scopeStep1(@Value("#{jobParameters[requestDate]}") String requestDate) {
	return stepBuilderFactory.get("scopeStep1")
    				 .tasklet((contribution, chunkContext) -> {
                             	log.info(">>> ");
                                return RepeatStatus.FINISHED;
                             })
                             .build();
}
  • @StepScope
    • Tasklet / Reader / Processor / Writer에서 사용할 수 있다.
@Bean
pulbic Step scopeStep2() {
	return stepBuilderFactory.get("scopeStep2")
    .tasklet(scopeStep2Tasklet(null))
    .build();
}

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

 

  • Type
    • Spring Batch의 JobParameter는 Long / String / Double / Date 타입들을 지원한다.
    • Enum / LocalDate / LocalDateTime은 지원하지 않는다.
      • 그렇다면?
        • @Value의 특성을 이용하면 String을 매번 LocalDateTime으로 변경하지 않아도 된다. (아래 코드 참고)
          • setter메소드에 @Value를 선언 문자열로 받은뒤 원하는 타입으로 세팅
@Slf4j
@Getter
@NoArgsConstructor
public class CreateDateJobParameter {
	private LocalDate localDate;
    
    @Value("#{jobParameters[createDate]}")
    public void setCreateDate(String createDate) {
    	DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        this.createDate = LocalDate.parse(createDate, formatter);
    }
}

 

@JobScope로 설정해놨기 때문에 Job이 실행될 때 Bean이 실행된다. 그러면 job실행되는 시점에 jobParameter Bean이 생성되서 값이 세팅된 다음에 CreateDateJobParameter에 Injection이 된다.

public class JObParameterBatchConfiguration {
	private final CreateDateJobParameter jobParameter;
    
    @Bean(BATCH_NAME + "jobParameter")
    @JobScope
    public CreateDateJobParameter jobParameter() {
    	return new CreateDateJobParameter():
    }
}

 

그 다음부터는 아래와 같이 사용하면 된다.jobParameter.getCreateDate()만 호출하면 된다. 

@Bean(name = BATCH_NAME + "_reader")
@StepScope
public JpaPagingItemReader<Product> reader() {
	Map<String, Object> params = new HashMap<>();
    params.put("createDate", jobParameter.getCreateDate()); // 어디에서나 LocalDate을 가져올 수 있음
    
    return new JpaPagingItemReaderBuilder<Product>()
    			.name(BATCH_NAME + "_reader")
                .entityManagerFactory(entityManagerFactory)
                .pageSize(chunkSize)
                .queryString("SELECT p FROM Product p WHERE p.createDate = :createDate")
                .parameterValues(params)
                .build();
}

 

  • @JobScope, @StepScope의 특징(Late Binding)을 활용해보기
    •  @JobScope나 @StepScope가 선언된  Bean의 경우에는 Job이나 Step이 실행될 때 Bean이 생성되는 특징을 가진다. (일반 Spring처럼 애플리케이션이 로딩될 때 Bean이 생성되는 것이 아니라)
    • 그 뜻은 애플리케이션 실행 후에도 동적으로 reader / processor / writer bean 생성이 가능하다는 뜻
      • 예를 들아보자
        • 정산하는 시스템에서 ERP 연동이 2-30개가 되는데 하는 일이 비슷
        • 주문데이터 긁어와서 어디에 보내는 것~ 파라미터가 주문이냐 매출이냐 광고냐 그리고 읽어와야 될 테이블 이 값만 다르고 다른 건 전부 동일 
        • 그럴 때 마다 같은 클래스를 계속 생성할 수 없으니 LateBinding을 이용해서 파라미터로 주문으로 던지면 주문 테이블에서 읽어오는 리더로 바꿔서 배치를 돌리고, 광고면 광고 테이블에서 읽어오는 리더로 바꿔서 배치를 돌리는 것이다.
private StimpleStepBuilder<EaiEntity, EaiItem> readerAndProcessor(String dealCode, String txDateStr) {
	EaiReaderParameterDato parameterDto = createParameter(dealCode, txDateStr);
    
    EaiTaskletType readerProcessorType = EaiDatailType.findTaskletType(dealCode);
    EaiReaderFactory readerCreator = readerProcessorType.getReaderCreator();
    
    return stepBuilderFactory.get(stepName)
    		 	.<~>chunk(chunkSize)
                             .reader(readerCreator.create(chunkSize, emf, parameterDto)) 
                             .processor(eaiProcessor);
}

+ Recent posts