스프링 배치 가이드
- 지난 포스팅에서 튜토리얼 보고 따라해봤는데, 이번에는 개념부터 천천히 공부해보자.
- 책을 보고 공부하려 했으나, 스프링과 부트의 배치 사용 문법이 많이 달라 이동욱님의 블로그를 보고 공부했다.
https://devhooney.tistory.com/140
1. ItemProcessor
- ItemProcessor는 Reader에서 넘겨준 데이터를 개별 건으로 가공하고 처리한다.
- ItemProcessor를 사용하는 방법은 2가지이다.
- 변환
- Reader에서 읽은 데이터를 원하는 타입으로 변환해서 Writer에 넘겨줄 수 있다.
- 필터
- Reader에서 넘겨준 데이터를 Writer로 넘겨줄 지 결정할 수 있다.
- null을 반환하면 Writer에 전달되지 않는다.
2. 사용 방법
- ItemProcessor는 인터페이스이고, 두 개의 제네릭 타입이 필요하다.
public interface ItemProcessor<I, O> {
/**
* Process the provided item, returning a potentially modified or new item for continued
* processing. If the returned result is {@code null}, it is assumed that processing of the item
* should not continue.
*
* A {@code null} item will never reach this method because the only possible sources are:
* <ul>
* <li>an {@link ItemReader} (which indicates no more items)</li>
* <li>a previous {@link ItemProcessor} in a composite processor (which indicates a filtered item)</li>
* </ul>
*
* @param item to be processed, never {@code null}.
* @return potentially modified or new item for continued processing, {@code null} if processing of the
* provided item should not continue.
* @throws Exception thrown if exception occurs during processing.
*/
@Nullable
O process(@NonNull I item) throws Exception;
}
- I: ItemReader에서 받을 데이터 타입
- O: ItemWriter에 보낼 데이터 타입
- Reader에서 읽은 데이터가 ItemProcessor의 process를 통과해서 Writer에 전달된다.
3. 변환
- Reader에서 읽은 타입을 변환하여 Writer에 전달
- 예시 코드(Teacher라는 도메인 클래스를 읽어와 Name 필드 (String 타입)을 Wrtier에 넘겨주도록 구성한 코드)
@Slf4j
@RequiredArgsConstructor
@Configuration
public class ProcessorConvertJobConfiguration {
public static final String JOB_NAME = "ProcessorConvertBatch";
public static final String BEAN_PREFIX = JOB_NAME + "_";
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final EntityManagerFactory emf;
@Value("${chunkSize:1000}")
private int chunkSize;
@Bean(JOB_NAME)
public Job job() {
return jobBuilderFactory.get(JOB_NAME)
.preventRestart()
.start(step())
.build();
}
@Bean(BEAN_PREFIX + "step")
@JobScope
public Step step() {
return stepBuilderFactory.get(BEAN_PREFIX + "step")
.<Teacher, String>chunk(chunkSize)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
@Bean
public JpaPagingItemReader<Teacher> reader() {
return new JpaPagingItemReaderBuilder<Teacher>()
.name(BEAN_PREFIX+"reader")
.entityManagerFactory(emf)
.pageSize(chunkSize)
.queryString("SELECT t FROM Teacher t")
.build();
}
@Bean
public ItemProcessor<Teacher, String> processor() {
return Teacher::getName;
}
private ItemWriter<String> writer() {
return items -> {
for (String item : items) {
log.info("Teacher Name={}", item);
}
};
}
}
- 실행하면
- 잘 진행됐다.
4. 필터
- 필터는
Writer에 값을 넘길지 말지를 Processor에서 판단하는 것
- 예제 코드 (Teacher의 Id가 짝수인 경우 필터링하는 예제)
@Value("${chunkSize:1000}")
private int chunkSize;
@Bean(JOB_NAME)
public Job job() {
return jobBuilderFactory.get(JOB_NAME)
.preventRestart()
.start(step())
.build();
}
@Bean(BEAN_PREFIX + "step")
@JobScope
public Step step() {
return stepBuilderFactory.get(BEAN_PREFIX + "step")
.<Teacher, Teacher>chunk(chunkSize)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
@Bean
public JpaPagingItemReader<Teacher> reader() {
return new JpaPagingItemReaderBuilder<Teacher>()
.name(BEAN_PREFIX+"reader")
.entityManagerFactory(emf)
.pageSize(chunkSize)
.queryString("SELECT t FROM Teacher t")
.build();
}
@Bean
public ItemProcessor<Teacher, Teacher> processor() {
return teacher -> {
boolean isIgnoreTarget = teacher.getId() % 2 == 0L;
if(isIgnoreTarget){
log.info(">>>>>>>>> Teacher name={}, isIgnoreTarget={}", teacher.getName(), isIgnoreTarget);
return null;
}
return teacher;
};
}
private ItemWriter<Teacher> writer() {
return items -> {
for (Teacher item : items) {
log.info("Teacher Name={}", item.getName());
}
};
}
}
- 실행하면
- 짝수를 건너서 1, 3만 출력됐다.
- jojoldu 이동욱님의 블로그를 참고해서 한번 씩 따라해봤는데, 정말 기초수준의 맛만 본거 같다.
- 회사에서 프리랜서 분이 배치를 이용하여 크롤링 작업을 하는 코드를 작성했는데, 보고 공부를 더 해봐야겠다.
- 참고
https://jojoldu.tistory.com/347?category=902551
'개발 > Java&Kotlin' 카테고리의 다른 글
[Java] 생성자 대신 빌더 사용하기 (0) | 2023.01.05 |
---|---|
[Java] 생성자 대신 정적 팩토리 메소드 사용하기 (1) | 2023.01.01 |
[Spring] 스프링 배치(Spring Batch) 가이드 따라가기 (6) (0) | 2022.12.20 |
[Spring] 스프링 배치(Spring Batch) 가이드 따라가기 (5) (0) | 2022.12.18 |
[Spring] 스프링 배치(Spring Batch) 가이드 따라가기 (4) (0) | 2022.12.14 |