들어가기 전
이전 글 에서 Spring Batch 실행을 위한 프로젝트 환경 구성 및 예제 Job 을 작성 후 실행해 봤습니다. 그렇다면 Spring Batch 는 Job 을 어떤 식으로 생성하고 실행시키는지에 대해 이번 글을 통해서 알아 보도록 하겠습니다.
Step
다음과 같이 Tasklet 으로 구성된 Step 을 Bean 으로 등록합니다.
@Bean
public Step step(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.tasklet(tasklet(), transactionManager)
.build();
}
먼저 StepBuilder 란 JobRepository 및 Listener 와 같은 공통 속성에 대한 액세스를 제공하는 유틸리티 클래스로 StepBuilder 에서 제공하는 메소드에 따라 적절한 하위 빌더 클래스가 생성됩니다.
위의 예제 코드에서는 사용자 정의 Tasklet 기반으로 하는 Step 단계를 생성하기 위한 TaskletStepBuilder 가 생성됩니다. TaskletStepBuilder 의 상속 구조도는 다음과 같습니다.
기본적으로 모든 빌더는 StepBuilderHelper 을 상속 받고 있으며 해당 클래스는 Step 을 생성하는데 공통적으로 필요한 기능을 제공합니다.
다음은 StepBuilderHelper 가 제공하는 주요 메소드입니다.
StepBuilderHelper 클래스는 Micrometer 와 관련된 ObservationConvention 을 구성하는 기능을 제공하는데 이 부분은 제가 완전히 무지한 상태라 넘어가도록 하겠습니다. 😓
Micrometer 는 Spring Application 에서 메트릭을 남기기 위한 facade 로 Spring Batch 는 ObservationConvention 의 구현체로 BatchStepObservationConvention 을 통해 StepContext 상태를 추적하는 기능을 제공하는 것 같습니다. 이 부분은 추후에 학습한 후 작성하도록 하겠습니다. 자세한 내용은 해당 페이지를 참고 부탁 드립니다.
- startLimit: CommonStepProperties 의 startLimit property 에 값을 저장합니다. 해당 설정 값만큼 Step 이 실행 가능함을 의미합니다.
- listener(object):
BeforeStep
,AfterStep
어노테이션이 명시된 메소드가 존재하는 리스너를 StepListenerFactoryBean 에 등록합니다. - listener(StepExecutionListener): Step 의 라이프사이클을 관리하는 StepExecutionListener 를 등록합니다. beforeStep, afterStep 관련한 메소드를 정의할 수 있습니다.
- allowStartIfComplete: 해당 메소드에 인자를
true
로 설정하면 JobInstance 해당 Step 도 포함하여 재실행합니다. - enhance: 인자로 AbstractStep 을 받습니다. 현재 StepBuilderHelper 에서 관리 중인 모든 properties 를 인자로 넘어온 Step 에 넘겨줍니다.
TaskLetStep 은 성공한 Step의 BatchStatus 를 Completed 로 관리합니다. 때문에 Step 을 재실행 시키면 실패한 Step 만을 재실행시키게 됩니다. 해당 메소드 인자를
true
로 설정하면 Completed 임에도 재 실행 하게 됩니다.
위와 같이 StepBuilderHelper 에서 제공하는 메소드를 통해 Step 을 생성하는데 필요한 속성들을 설정합니다. 그 후 AbstractTaskletStepBuilder 은 StepBuilderHelper 가 수집한 구성 요소를 통해 build
메소드를 통해 TaskletStep 을 생성하여 반환합니다.
public TaskletStep build() {
registerStepListenerAsChunkListener();
TaskletStep step = new TaskletStep(getName());
super.enhance(step);
step.setChunkListeners(chunkListeners.toArray(new ChunkListener[0]));
if (this.transactionManager != null) {
step.setTransactionManager(this.transactionManager);
}
if (transactionAttribute != null) {
step.setTransactionAttribute(transactionAttribute);
}
if (stepOperations == null) {
stepOperations = new RepeatTemplate();
if (taskExecutor != null) {
TaskExecutorRepeatTemplate repeatTemplate = new TaskExecutorRepeatTemplate();
repeatTemplate.setTaskExecutor(taskExecutor);
repeatTemplate.setThrottleLimit(throttleLimit);
stepOperations = repeatTemplate;
}
((RepeatTemplate) stepOperations).setExceptionHandler(exceptionHandler);
}
step.setStepOperations(stepOperations);
step.setTasklet(createTasklet());
step.setStreams(streams.toArray(new ItemStream[0]));
try {
step.afterPropertiesSet();
}
catch (Exception e) {
throw new StepBuilderException(e);
}
return step;
}
TaskletStep 을 생성한 객체를 enhance()
의 인자로 넘긴 후 이를 위임한 다음 서브 클래스에서 createTasklet()을 위임하여 실제 Tasklet 을 생성합니다. 이렇게 생성된 Step 은 Bean 으로 등록되어 스프링 컨테이너에 저장되게 됩니다.
Job
다음과 같이 Step 을 가지는 Job 을 Bean 으로 등록합니다.
@Bean
public Job myJob(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new JobBuilder("myJob", jobRepository)
.start(step(jobRepository, transactionManager))
.build();
}
먼저 JobBuilder 란 JobRepository 와 같은 공통 속성에 대한 액세스를 제공하는 유틸리티 클래스로 JobBuilder 에서 제공하는 메소드에 따라 적절한 하위 빌더 클래스가 생성됩니다.
위 예제 코드에서는 Step 을 인자로 받는 start()
메소드를 사용하는데 JobBuilder 는 내부적으로 SimpleJobBuilder 를 생성하여 SimpleJob 을 생성합니다. 반대로 Flow 를 인자로 받는 start()
또는 Step 을 인자로 받는 flow()
메소드를 사용하게 되면 JobBuilder 는 내부적으로 FlowJobBuilder 를 생성하여 FlowJob 을 생성하게 됩니다. SimpleJobBuilder 의 기본 상속 구조도는 다음과 같습니다.
기본적으로 모든 빌더는 JobBuilderHelper 을 상속 받고 있으며 해당 클래스는 Job 을 생성하는데 공통적으로 필요한 기능을 제공합니다. 다음은 JobBuilderHelper 가 제공하는 주요 메소드입니다.
JobBuilderHelper 클래스 또한 StepBuilderHelper 와 같이 Micrometer 와 관련된 ObservationConvention 을 구성하는 기능을 제공하는데 이 부분은 제가 완전히 무지한 상태라 넘어가도록 하겠습니다. 😓
- validator: job parameters 의 유효성을 검사하는데 사용할 인터페이스를 등록합니다. DefaultJobParametersValidator 을 기본 구현체로 제공합니다.
- incrementer: job parameters 의 시퀀스와 같이 필요한 값을 증가시켜 다음에 사용될 job parameters 객체를 반환합니다. RunIdIncrementer 을 기본 구현체로 제공합니다.
- listener(object):
BeforeJob
,AfterJob
어노테이션이 명시된 메소드가 존재하는 리스너를 JobListenerFactoryBean 에 등록합니다. - listener(JobExecutionListener): Job 의 라이프사이클을 관리하는 JobExecutionListener 를 등록합니다. beforeJob, afterJob 관련한 메소드를 정의할 수 있습니다.
- preventRestart: Job 이 실패한 경우에 다시 시작하지 못하도록 플래그를 설정합니다. AbstractJob 클래스에 있는
restartable
맴버 편수를false
로 설정합니다. - enhance: 인자로 AbstractJob 을 받습니다. 현재 JobBuilderHelper 에서 관리 중인 모든 properties 를 인자로 넘어온 Job 에 넘겨줍니다.
위와 같이 JobBuilderHelper 에서 제공하는 메소드를 통해 Job 을 생성하는데 필요한 속성들을 설정합니다. 그 후 AbstractTaskletJobBuilder 은 JobBuilderHelper 가 수집한 구성 요소를 통해 build
메소드를 통해 Job 을 생성하여 반환합니다.
public Job build() {
if (builder != null) {
return builder.end().build();
}
SimpleJob job = new SimpleJob(getName());
super.enhance(job);
job.setSteps(steps);
try {
job.afterPropertiesSet();
}
catch (Exception e) {
throw new JobBuilderException(e);
}
return job;
}
SimpleJob 을 생성한 객체를 enhance()
의 인자로 넘긴 후 이를 위임한 다음 Job 가지고 있는 Step 목록을 셋팅합니다. 이렇게 생성된 Job 은 Bean 으로 등록되어 스프링 컨테이너에 저장되게 됩니다.
위와 같이 Job 과 Step 은 Builder Pattern 을 이용하여 유사한 방법으로 생성이 되어집니다. 하지만 Job 은 단순한 일련의 연속인 Step 과는 다르게 더 나아가 여러 워크플로우와 재시도 및 복구, 병렬 처리와 같은 추가 기능을 제공합니다. 위와 같은 기능을 제공하는 Job 을 생성해주는 빌더들에 대해 알아보겠습니다.
SimpleJobBuilder
작성 예정
FlowJobBuilder
작성 예정
실행
작성 예정
오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.
'Spring > Batch' 카테고리의 다른 글
[Spring] Spring Batch 시작하기 01 (1) | 2024.01.14 |
---|---|
[Spring] Spring Batch란? (2) | 2023.12.18 |