본문 바로가기

SPRING

[SPRING] Spring batch 와 Spring Scheduler 예제

Spring Batch

: 대용량 일괄처리의 편의를 위해 설계된 Spring Boot 배치 프레임워크로, 배치 프로그램의 기본적 구성 요소인 로깅, 병렬처리, 대용량 데이터 처리를 위한 작업들을 제공한다.

 

Job & Step

스프링 배치의 가장 기본이 되는 구성요소로 Job 안에는 여러 Step이 존재하고, Step 안에 Tasklet 혹은 Reader & Processor & Writer 묶음이 존재하며 다음과 같은 예시를 들 수 있다.

 

JOB(name = "miracleMorning")

: 매일 아침 6시에 일어나면 커피를 마시고 운동을 간다 만약 그렇지 못하면 물을 마시고 운동을 간다

Step(name = "wakeUp")

: 일어난다

Step(name = "drinkCoffee")

: 커피를 마신다

Step(name = "drinkWater")

: 물을 마신다

Step(name = "exercise")

: 운동을 한다

 

이렇게 Job 을 선언하고 해당 Job을 수행하기 위한 Step 을 정의 한다

 

Tasklet vs Chunk

실제 처리 로직이 들어가 있는 빈이다. 스프링배치에 처리를 하는 방식은 크게 Chunk 방식과 Tasklet 방식으로 나눌수 있다. Chunk 방식은 세가지 클래스 빈 ItemReader, ItemProcessor, ItemWriter 를 구현하고 이미 스프링 배치에서 작성해놓은 클래스들이 있어 그것을 이용하면 된다. 물론 직접 상속받아 구현할 수도 있다. Tasklet 방식은 Tasklet 인터페이스만 구현하면 되고 개발자가 직접 작성한다. for loop 를 돌면 숫자를 출력하고 종료되면 RepeatStatus.FINISHED 를 반환 배치에 정상 종료를 전달한다

 

 

이제 위에서 정의한 예제를 직접 적용해보자!

 

 

Spring Batch 예제

 

먼저 batch 의존성을 추가해준다

implementation 'org.springframework.boot:spring-boot-starter-batch'

 

@SpringBootApplication 어노테이션이 붙은 파일에 @EnableBatchProcessing 을 붙여준다

 

@SpringBootApplication
@EnableBatchProcessing
public class AdvancedSpringApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdvancedSpringApplication.class, args);
    }

}

 

@Slf4j
@Configuration
@RequiredArgsConstructor
public class BatchJobConfig {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job miracleMorning() {
        return jobBuilderFactory.get("miracleMorning")
                .start(wakeUp())
                .on("COMPLETED")
                .to(drinkCoffee())
                .on("*")
                .to(exercise())
                .on("*")
                .end()

                .from(wakeUp())
                .on("*")
                .to(drinkWater())
                .on("*")
                .to(exercise())
                .on("*")
                .end()
                .end().build();
    }

    @Bean
    public Step wakeUp() {
        return stepBuilderFactory.get("wakeUp")
                .tasklet((contribution, chunkContext) -> {
                    log.info("----- wakeUp");

                    String result = "COMPLETED";

                    //Flow에서 on은 RepeatStatus가 아닌 ExitStatus를 바라본다.
                    if (result.equals("COMPLETED"))
                        contribution.setExitStatus(ExitStatus.COMPLETED);
                    else if (result.equals("FAIL"))
                        contribution.setExitStatus(ExitStatus.FAILED);
                    else if (result.equals("UNKNOWN"))
                        contribution.setExitStatus(ExitStatus.UNKNOWN);

                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step drinkCoffee() {
        return stepBuilderFactory.get("drinkCoffee")
                .tasklet((contribution, chunkContext) -> {
                    log.info("----- drinkCoffee");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step drinkWater() {
        return stepBuilderFactory.get("drinkWater")
                .tasklet((contribution, chunkContext) -> {
                    log.info("----- drinkWater");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step exercise() {
        return stepBuilderFactory.get("exercise")
                .tasklet((contribution, chunkContext) -> {
                    log.info("----- exercise");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }
 }

 

 

 

 

 

Spring Scheduler 적용

 

scheduler 의존성 주입을 해준다.

    implementation 'org.springframework.boot:spring-boot-starter-quartz'

 

@SpringBootApplication 어노테이션이 붙은 파일에 @EnableScheduling 을 붙여준다

@SpringBootApplication
@EnableJpaAuditing
@EnableBatchProcessing
@EnableScheduling
public class AdvancedSpringApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdvancedSpringApplication.class, args);
    }

}

 

@Slf4j
@Component
@RequiredArgsConstructor
public class BatchSchedule {

    private final JobLauncher jobLauncher;
    private final BatchJobConfig batchJobConfig;

    @Scheduled(cron = "*/5 * * * * *")
    public void runJob() {
        // job parameter 설정
        Map<String, JobParameter> confMap = new HashMap<>();
        confMap.put("time", new JobParameter(System.currentTimeMillis()));
        JobParameters jobParameters = new JobParameters(confMap);

        try {
            jobLauncher.run(batchJobConfig.miracleMorning(), jobParameters);
        } catch (JobExecutionAlreadyRunningException | JobInstanceAlreadyCompleteException
                 | JobParametersInvalidException | org.springframework.batch.core.repository.JobRestartException e) {
            log.error(e.getMessage());
        }
    }
}

 

위 코드는 5초에 한번씩 miracleMorining batch를 실행하는 스케쥴러를 뜻한다 여기서 @Scheduled어노테이션 속성으로 붙는 cron은 반복 설정을 뜻하는데

*(에스더리스크) 를 앞에서부터 초(0-50) 분(0-50) 시간(0-23) 일(1-31) 월(1-12) 요일(0-7)을 의미한다.

참고로 요일에서 0과 7은 일요일이며 1부터 월요일이고 6은 토요일을 뜻한다.

 

 

 

 

 

 

끄읏 -!

 

 

참고

https://warpgate3.tistory.com/entry/Spring-Batch-Sample-Code-1 

https://jojoldu.tistory.com/325