SpringBatch의 TaskletStep 수행과정을 예제코드 디버깅으로 분석하기

반응형
728x90
반응형

들어가며

간단한 SimpleJob 예제의 TaskletStep의 실행 흐름을 디버깅을 통해 직접 확인해보자.

 

 

예제코드

TaskletStepArchitectureConfiguration.java
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.List;

/*
--job.name=taskletArchitectureStepJob
 */

@Configuration
@RequiredArgsConstructor
public class TaskletStepArchitectureConfiguration {

    // job 생성
    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job taskletArchitectureStepJob() {
        return this.jobBuilderFactory.get("taskletArchitectureStepJob")
                .incrementer(new RunIdIncrementer())
                .start(taskletArchitectureStepStep1())
                .listener(new StepExecutionListener() {
                    // before
                    @Override
                    public void beforeStep(StepExecution stepExecution) {

                    }
                    // after
                    @Override
                    public ExitStatus afterStep(StepExecution stepExecution) {
                        return null;
                    }
                })
                .build();
    }

    @Bean
    public Step taskletArchitectureStepStep1() {
        return stepBuilderFactory.get("taskletArchitectureStepStep1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("taskletArchitectureStepStep1");
                        return RepeatStatus.FINISHED;
                    }
                })
                .build();
    }
}

 

 

TaskletStep 실행흐름

출처 : 인프런 '스프링 배치 - Spring Boot 기반으로 개발하는 Spring Batch' 강의

 

 

SimpleJob

SimpleJob 실행흐름은 아래 포스팅을 참고하자.

https://devfunny.tistory.com/932

 

SpringBatch의 SimpleJob 수행과정을 예제코드 디버깅으로 분석하기

들어가며 간단한 SimpleJob 예제의 실행 흐름을 디버깅을 통해 직접 확인해보자. 이번기회에 실행 흐름을 정리해서 앞으로 BatchJob 예제를 수행할때마다 흐름을 따라갈 수 있도록 글을 남긴다. 예제

devfunny.tistory.com

 

 

디버깅을 통한 실행흐름 분석

1) SimpleJob.java > doExecute()

SimpleJob의 doExecute()에서 step을 반복적으로 수행

 

▶ Step1이 들어가있음을 확인할 수 있다.

 

2) SimpleStepHandler.java > handleStep()

 

 StepExecution을 생성한다.

 

▶ 생성한 StepExecution을 ExecutionContext에 셋팅한다.

 

 

3) AbstractStep.java > execute()

Listener가 있었다면 Step 수행 전에 수행하고, doExecute() 메서드를 통해 Step을 실행한다.

 

 

4) TransctionTemplate.java > execute()

 

5) TaskletStep.java > doExecute()

iterate()를 통해서 반복 수행된다. 콜백함수인, doIncChunkContext에서 트랜잭션 처리를 위한 로직을 수행한다. 

 

6) StepContextRepeatCallback.java > doInIteration()

 

7) TransactionTemplate.java > execute()

 

8) TaskletStep.java > doInTransaction()

tasklet의 execute()를 통해서 수행시킨다. 여기서 우리가 TaskletStepArchitectureConfiguration에서 정의한 Tasklet 익명함수 로직이 수행된다.

 

▶ result가 null이면 RepeatStatus.FINISHED로 설정해주므로, null일때와 동일하다.

if (result == null) {
    result = RepeatStatus.FINISHED;
}

 

▶ apply() 메서드를 호출하여 Step의 결과 카운팅을 셋팅한다.

 

apply()

 

9) AbstractStep.java > execute()

Step 실행 이후, ExitStatus, BatchStatus를 셋팅한다.

 

 

실행결과
taskletArchitectureStepStep1

 

 

 

RepeatStatus.CONTINUABLE로 바꿔보자

TaskletStepArchitectureConfiguration.java
@Bean
public Step taskletArchitectureStepStep1() {
    return stepBuilderFactory.get("taskletArchitectureStepStep1")
            .tasklet(new Tasklet() {
                @Override
                public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                    System.out.println("taskletArchitectureStepStep1");
                    return RepeatStatus.CONTINUABLE;
                }
            })
            .build();
}

 

 

디버깅을 통한 실행흐름 분석 (위 분석의 8) 이후부터 다시 보자)

8) TaskletStep.java > doInTransaction()

Step 수행 이후, 마지막 부분에서 result가 "CONTINUABLE"이다.

 

9) TaskletStep.java > doExecute()

 

10) RepeatTemplate > executeInternal()

CONTINUABLE일때 while() 반복문이 계속 수행된다.

while(true) {
    boolean var81 = false;

    try {
        ...
        
        for(i = 0; i < this.listeners.length; ++i) {
            interceptor = this.listeners[i];
            interceptor.before(context);
            runnin=g = running && !this.isMarkedComplete(context);
        }

        if (running) {
            try {
                result = this.getNextResult(context, callback, state);
                this.executeAfterInterceptors(context, result);
            } catch (Throwable var82) {
                this.doHandle(var82, context, deferred);
            }

            if (this.isComplete(context, result) || this.isMarkedComplete(context) || !deferred.isEmpty()) {
                running = false;
            }
        }
        
        ...

 

11) RepeatTemplate.java > getNextResult()

 

12) StepContextRepeatCallback.java > doInIteration()

 

위 과정을 반복해서, 계속해서 배치를 수행하게된다.

null 또는 RepeatStatus.FINISHED를 리턴해야 수행을 한 후, 배치가 종료됨을 알 수 있다.

 

 

실행결과
taskletArchitectureStepStep1
taskletArchitectureStepStep1
taskletArchitectureStepStep1
..

 

 

반응형

Designed by JB FACTORY