Spring Batch 5 버전을 어떻게 사용하는지 간단한 예시를 통해 알아보려 합니다.
환경
- Spring Batch 5.1.0
- Spring Boot 3.1.3
- Java 17
- MairaDB(MySQL)
설치
// Spring Batch
implementation 'org.springframework.boot:spring-boot-starter-batch'
// spring-batch-core
implementation 'org.springframework.batch:spring-batch-core:5.1.0'
application.properties 설정
### spring batch
spring.batch.job.enabled=true
spring.batch.jdbc.initialize-schema=always
initialize-schema=always를 통해 Spring Batch에 필요한 테이블을 자동 생성합니다.
JAVA 코드
원하는 위치에 Configuratoin 파일 생성
기본
등록된 step들을 실행하는 코드입니다.
simpleStep1이 실행된 이후 simpleStep2가 실행이 됩니다.
SpringBatchConfiguration.java
package com.study.CSStudy.api.config.batch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Slf4j
@Configuration
public class SpringBatchConfiguration {
@Bean
public Job simpleJob1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new JobBuilder("simpleJob", jobRepository)
.start(simpleStep1(jobRepository, platformTransactionManager))
.next(simpleStep2(jobRepository, platformTransactionManager))
.build();
}
@Bean
public Step simpleStep1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep1", jobRepository)
.tasklet(testTasklet(), platformTransactionManager)
.build();
}
@Bean
public Step simpleStep2(JobRepository jobRepository,PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep2", jobRepository)
.tasklet(test2Tasklet(), platformTransactionManager)
.build();
}
@Bean
public Tasklet testTasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> This is Step1");
return RepeatStatus.FINISHED;
});
}
@Bean
public Tasklet test2Tasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> This is Step2");
return RepeatStatus.FINISHED;
});
}
}
- 메소드 설명
- simpleJob1 : Job을 등록하는 메소드 입니다.
- step을 등록하고, 조건(실패했을 경우 등)을 설정하여 Job을 등록합니다.
- .start()를 통해 step을 등록하고, 그 이후에 작동할 step은 .next()를 통해 등록합니다.
- simpleStep1, simpleStep2 : Step을 등록하는 메소드 입니다.
- Step 이름과 repository(DB)를 등록하고 작동할 tasklet을 등록합니다.
- 여기서 repository는 Spring Batch가 작동하기 위해 필요한 정보를 담는 DB와 연동하는 repository입니다.
- testTasklet, test2Tasklet : Tasklet을 등록하는 메소드 입니다.
- 여기에 동작할 코드를 작성합니다.
- return RepeatStatus.FINISHED;를 이용해 끝났다는 것을 알립니다.
step에서 에러가 발생 한 경우 이에 대한 대처
만약 step이 실행 중 실패 혹은 에러가 발생 할 경우 이에 따른 행동을 실행하길 원할 수 있습니다.
그럴 경우 아래와 같이 설정하면 됩니다.
SpringBatchConfiguration.java
package com.study.CSStudy.api.config.batch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Slf4j
@Configuration
public class SpringBatchConfiguration {
@Bean
public Job simpleJob1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new JobBuilder("simpleJob", jobRepository)
.start(simpleStep1(jobRepository, platformTransactionManager))
.on(ExitStatus.FAILED.getExitCode())// Failed 경우
.to(simpleStep1Failed(jobRepository, platformTransactionManager)) // failedTasklet 으로 이동하여 실행
.on("*") // failedTasklet 결과와 상관없이
.end() // 종료
.from(simpleStep1(jobRepository, platformTransactionManager)) //simpleStep1 로부터
.on("*") // 앞서 설정한 Failed 제외하고
.to(simpleStep2(jobRepository, platformTransactionManager))// simpleStep2 실행
.on("*") // simpleStep2 결과 상관 없이
.end()// 종료
.end()
.build();
}
@Bean
public Step simpleStep1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep1", jobRepository)
.tasklet(errorTasklet(), platformTransactionManager) // 에러 발생하는 tasklet으로 설정
.build();
}
@Bean
public Step simpleStep2(JobRepository jobRepository,PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep2", jobRepository)
.tasklet(test2Tasklet(), platformTransactionManager)
.build();
}
@Bean
public Step simpleStep1Failed(JobRepository repository, PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep1Failed", repository)
.tasklet(failedTasklet(), platformTransactionManager)
.build();
}
@Bean
public Tasklet testTasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> This is Step1");
return RepeatStatus.FINISHED;
});
}
@Bean
public Tasklet test2Tasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> This is Step2");
return RepeatStatus.FINISHED;
});
}
@Bean
public Tasklet errorTasklet(){
return ((contribution, chunkContext) -> {
contribution.setExitStatus(ExitStatus.FAILED);
return RepeatStatus.FINISHED;
});
}
@Bean
public Tasklet failedTasklet(){
return ((contribution, chunkContext) -> {
log.info("failed");
return RepeatStatus.FINISHED;
});
}
}
메소드 설명
- simpleJob1
- .start() : step1 실행
- .on() : step1이 실행된 결과 값에 따른 분기점 선택(ex : 성공, 실패 등)
- .to() : 분기점에 대해 일어날 step 설정
- .on("*") : .to()에서 설정한 step의 결과와 상관없이 밑에 내용을 실행
- .end() 종료
- .from() : 해당 step이 끝난 이후.(단, 앞서 설정한 분기점이 있을 경우 그 분기점을 제외 하고 밑에 내용 실행)
- 이하 위 .on()~.end()까지 동일
- errorTasklet
- 리턴 값(contribution.setExitStaus)을 ExitStatus.FAILED로 설정해서 실패했다고 리턴값을 알림
- 위 simpleJob1에서 에러가 발생한 경우를 실행하기 위해 일부러 실패한 리턴으로 설정
- failedTasklet
- 위 simpleJob1 - step1에서 실패한 경우 실행하는 tasklet으로 설정
Tasklet을 별도의 Component로 설정
@Bean 등록 말고 별도의 Component로 설정하여 좀 더 코드를 나눠서 관리 혹은 개발 할 수 있음.
SpringBatchConfiguration.java
package com.study.CSStudy.api.config.batch;
import com.study.CSStudy.api.component.FirstTasklet;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Slf4j
@RequiredArgsConstructor
@Configuration
public class SpringBatchConfiguration {
private final FirstTasklet firstTasklet;
@Bean
public Job simpleJob1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager) {
return new JobBuilder("simpleJob", jobRepository)
.start(simpleStep1(jobRepository, platformTransactionManager))
.next(simpleStep2(jobRepository, platformTransactionManager))
.build();
}
@Bean
public Step simpleStep1(JobRepository jobRepository, PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep1", jobRepository)
.tasklet(firstTasklet, platformTransactionManager)
.build();
}
@Bean
public Step simpleStep2(JobRepository jobRepository,PlatformTransactionManager platformTransactionManager){
return new StepBuilder("simpleStep2", jobRepository)
.tasklet(test2Tasklet(), platformTransactionManager)
.build();
}
@Bean
public Tasklet test2Tasklet(){
return ((contribution, chunkContext) -> {
log.info(">>>>> This is Step2");
return RepeatStatus.FINISHED;
});
}
}
FirstTasklet.java
package com.study.CSStudy.api.component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@StepScope
public class FirstTasklet implements Tasklet {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
log.info("First Tasklet : first Step");
return RepeatStatus.FINISHED;
}
}
- execute 안에 원하는 기능을 작성하면 됨.
'개발잡담 > Back-End' 카테고리의 다른 글
Spring Boot에서 영상 스트리밍으로 받기 (feat. React) (0) | 2024.02.03 |
---|---|
Spring Boot에서 파일 다운로드 (feat. React) (0) | 2024.02.02 |
로그가 필요해 - 서론 (0) | 2023.11.02 |
Spring은 어떻게 여러 개의 요청을 동시에 처리할까? (0) | 2023.09.26 |
Spring Boot에서 MQTT 사용하기 (0) | 2023.05.19 |