BackEnd/Spring Batch

[Spring Batch 정리하기] 4. 실행하기

Wonol 2024. 7. 29. 09:02
반응형

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 바인딩 과정

  1. 어플리케이션이 구동되면 Spring 의 ApplicationContext 가 Bean 을 생성하고 관리
  2. 클래스에서 @JobScope / @StepScope 어노테이션이 존재하는지 확인
    - 존재하지 않는다면 기본적인 싱글톤 Bean 을 생성(만약 @Value 어노테이션 선언 시 오류 발생)
    - 존재한다면 해당 Bean 의 Proxy 객체를 생성
  3. 설정이 끝나면 스프링 초기화가 완료, Job 실행(JobLauncher)
  4. Job 은 Step 의 실제 Bean 이 아닌 Proxy 객체를 저장
  5. Proxy 객체는 실제 Step 메소드(step())를 호출할 때 실제 Bean 객체를 참조 -> 해당 시점에 StepBean 생성
  6. 5번에서 프록시 객체가 실제 메소드를 호출할 때 참조할 Bean 을 JobScope 에서 조회(JobScope 는 JobContext 를 통해 조회)
  7. JobContext 에서는 실제 Bean 이 존재하면 해당 Bean 을 꺼내 참조하여 실제 Step 수행
  8. JobContext 에서 실제 Bean 이 존재하지 않으면 스플이 BeanFactory 를 통해 실제 Step 생성 -> 해당 시점에 실제 step() 메소드를 호출해서 Bean 을 생성 및 @Value 바인딩 처리 및 진행
  9. 생성된 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

반응형