[Spring Batch 정리하기] 4. 실행하기
1. JobLauncher
public interface JobLauncher {
public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException,
JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException;
}
1-1) 기본 개념
- 배치 Job 을 실행시키는 역할
- Job 과 JobParameters 를 인자로 받아 배치를 수행하고 끝나면 JobExecution 을 Return
- Application 이 구동될 때 JobLauncher Bean 이 자동 생성
2. JobBuilderFactory & JobBuilder
- Spring Batch 는 Job 과 Step 을 쉽게 생성할 수 있도록 Builder 클래스를 제공
2-1) JobBuilderFactory
- JobBuilder 를 생성하는 팩토리 클래스
- jobBuilderFactory.get("jobName") -> "jobName" 은 스프링 배치가 Job 을 실행시킬 때 참조하는 Job 이름
@Bean(name = "BatchJob")
public Job job() {
return jobBuilderFactory.get("BatchJob")
.start(step())
.on("COMPLETED")
.to(processorStep(null, null))
.end()
.build();
}
2-2) JobBuilder
- SimpleJobBuilder
- Job 실행과 관련된 여러 설정 API 제공 - FlowJobBuilder
- 내부적으로 FlowBuilder 를 반환함으로서 Flow 실행과 관련된 여러 설정 API 제공
2-3) 아키텍처 & 클래스 상속 구조
3. StepBuilderFactory / StepBuilder
3-1) StepBuilderFactory
- StepBuilder 를 생성하는 팩토리 클래스
- stepBuilderFactory.get("stepName") -> "stepName" 은 스프링 배치가 Step 을 실행시킬 때 참조하는 Step 이름
@Bean(name="BatchJobStep")
@JobScope
public Step step() {
return stepBuilderFactory.get("BatchJobStep")
.tasklet((contribution, chunkContext) -> {
return RepeatStatus.FINISHED;
})
.build();
}
3-2) StepBuilder
- TaskletStepBuilder
- TaskletStep 을 생성하는 기본 빌더 클래스 - SimpleStepBuilder
- TaskletStep 을 생성하며 내부적으로 청크기반의 작업을 처리하는 ChunkOrientedTasklet 클래스를 생성 - PartionStepBuilder
- PartionStep 을 생성하며 멀티 스레드 방식으로 Job 을 실행 - JobStepBuilder
- JobStep 을 생성하여 Step 안에서 Job 을 실행 - FlowStepBuilder
- FlowStep 을 생성하여 Step 안에서 Flow 를 실행
4. SimpleJob
4-1) 기본개념
- Job 이 실행되면 해당 Job 은 순차적으로 Step 을 실행
- 모든 Step 이 완료되어야만 Job 이 성공적으로 완료(만약 중간 Step 에서 오류/실패가 된다면 해당 Job 은 실패로 완료)
- 맨 마지막 Step 의 BatchStatus 가 Job 의 최종 BatchStatus(배치 상태)
4-2) 흐름
public Job batchJob() {
return jobBuilderFactory.get("batchJob") // JobBuilder 를 생성하는 팩토리, Job 의 이름을 매개변수로 받음
.start(Step) // 처음 실행 할 Step 설정, 최초 한번 설정, 이 메서드를 실행하면 SimpleJobBuilder 반환
.next(Step) // 다음에 실행 할 Step 설정, 횟수는 제한이 없으며 모든 next() 의 Step 이 종료가 되면 Job 이 종료된다
.incrementer(JobParametersIncrementer) // JobParameter 의 값을 자동을 증가해 주는 JobParametersIncrementer 설정
.preventRestart(true) // Job 의 재 시작 가능 여부 설정, 기본값은 true
.validator(JobParameterValidator) // JobParameter 를 실행하기 전에 올바른 구성이 되었는지 검증하는 JobParametersValidator 설정
.listener(JobExecutionListener) // Job 라이프 사이클의 특정 시점에 콜백 제공받도록 JobExecutionListener 설정
.build(); // SimpleJob 생성
}
4-3) API 설정
- start() / next()
- start() : 처음 실행할 step 설정, 최초 한번 설정
- next() : 다음에 실행할 step 들을 순차적으로 연결, 여러변 설정이 가능하며 모든 next() 의 step 이 종료되면 Job 종료
- incrementer()
- 기존의 JobParameter 변경없이 동일한 Job 을 여러 번 수행하고자 할 때 사용
- RunIdIncrementer 구현체를 지원하며 인터페이스를 직접 구현 가능
4-4) 아키텍처
5. TaskletStep
5-1) 기본 개념
- Step 의 구현체 중 하나로 Tasklet 을 실행시키는 도메인 객체
- RepeatTemplate 를 사용해 Tasklet 의 구문을 트랜잭션 경계 내에서 반복 수행
- 스프링 배치에서 Step 의 실행 단위는 2가지로 나누어짐.
- Task 기반
- 단일 작업 기반으로 처리되는 것이 더 효율적인 경우
- Tasklet 구현체 사용
- 대량 처리를 하는 경우 Chunk 기반보다 복잡한 구현 필요 - Chunk 기반
- 하나의 큰 덩어리를 N 개씩 나누어 실행한다는 의미로 대량 처리를 하는 경우 효과적으로 수행
- ItemReader, ItemProcessor, ItemWriter 를 사용하며 청크 기반 전용 ChunkOrientedTasklet 구현체 사용
5-2) 예제
@Bean(name="BatchJobStep")
@JobScope
public Step step() {
return stepBuilderFactory.get("BatchJobStep") // StepBuilder 를 생성하는 팩토리, Step 이름을 매개변수로 받음
.tasklet((contribution, chunkContext) -> { // Tasklet 클래스 설정
return RepeatStatus.FINISHED;
})
.startLimit(10) // Step 의 실행 횟수 설정, 초과 시 오류 발생
.allowStartIfComplete(true) // Step 의 성공, 실패와 상관없이 항상 Step 을 실행하기 위한 설정
.listener(new StepExecutionListener() { // Step 라이프 사이클의 특정 시점에 콜백을 제공받는 Listener
@Override
public void beforeStep(StepExecution stepExecution) {
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
})
.build();
}
5-3) 아키텍쳐
6. FlowJob
6-1) 기본 개념
- Step 을 순차적으로만 구성하는 것이 아닌 특정한 상태에 따라 순서를 변경하도록 구성 가능
- Step 이 실패하더라도 Job 은 실패로 끝나지 않도록 해야 하는 경우
- Step 이 성공/실패에 따라 다르게 다음 Step 이 실행되어야 하는 경우
- Flow 와 Job 의 흐름에만 관여하고 비지니스로직은 Step 에서 동작
6-2) SimpleJob VS FlowJob
6-3) 예제
@Bean(name = "BatchJob")
public Job job() {
return jobBuilderFactory.get("BatchJob")
.start(step()) // Flow 시작하는 Step 설정
.on("COMPLETED") // Step 의 실행 결과로 ExitStatus 를 캐치하여 상태에 맞는 다음 Step 처리
.to(processorStep(null, null)) // 다음으로 이동할 Step 지정 -> step() 이 성공인 경우(processorStep 수행)
.on("FAILED") // 다음으로 이동할 Step 지정 -> step() 이 실패인 경우(end 배치 종료)
.end()
.from(processorStep(null, null)) // 이전 단계(processorStep)에서 정의한 Step 의 Flow 를 추가로 정의
.on("COMPLETED")
.to(finishStep())
.on("COMPELTED")
.end()
.end() // build() 앞에 위치하면 FlowBuilder 를 종료 -> Job 종료
.build();
}
6-4) 아키텍쳐
7. @JobScope / @StepScope
7-1) Proxy 객체 생성
- @JobScope, @StepScope 어노테이션이 선언되면 내부적으로 Bean 의 Proxy 객체가 생성 -> Job 실행 시 Proxy 객체가 실제 Bean 을 호출하여 해당 메소드를 실행
7-2) JobScope, StepScope
- Proxy 객체의 실제 대상이 되는 Bean 을 등록, 해제
- 실제 Bean 을 저장하고 있는 JobContext, StepContext 를 가짐
7-3) JobContext, StepContext
- 스프링 컨테이너에서 생성된 Bean 을 저장하는 컨텍스트 역할
- Job 실행 시점에서 Proxy 객체가 실제 Bean 을 참조할 때 사용
7-4) 스프링 어플리케이션 구동 부터 @Value 바인딩 과정
- 어플리케이션이 구동되면 Spring 의 ApplicationContext 가 Bean 을 생성하고 관리
- 클래스에서 @JobScope / @StepScope 어노테이션이 존재하는지 확인
- 존재하지 않는다면 기본적인 싱글톤 Bean 을 생성(만약 @Value 어노테이션 선언 시 오류 발생)
- 존재한다면 해당 Bean 의 Proxy 객체를 생성 - 설정이 끝나면 스프링 초기화가 완료, Job 실행(JobLauncher)
- Job 은 Step 의 실제 Bean 이 아닌 Proxy 객체를 저장
- Proxy 객체는 실제 Step 메소드(step())를 호출할 때 실제 Bean 객체를 참조 -> 해당 시점에 StepBean 생성
- 5번에서 프록시 객체가 실제 메소드를 호출할 때 참조할 Bean 을 JobScope 에서 조회(JobScope 는 JobContext 를 통해 조회)
- JobContext 에서는 실제 Bean 이 존재하면 해당 Bean 을 꺼내 참조하여 실제 Step 수행
- JobContext 에서 실제 Bean 이 존재하지 않으면 스플이 BeanFactory 를 통해 실제 Step 생성 -> 해당 시점에 실제 step() 메소드를 호출해서 Bean 을 생성 및 @Value 바인딩 처리 및 진행
- 생성된 StepBean 을 JobContext 에 저장하고, 이후 JobContext 에서 해당 Bean 을 꺼내어 사용
참고
- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B0%B0%EC%B9%98/dashboard