기존 Config 설정 기반의 추가 설정 하기
Spring Batch의 설정 과정과 실행 방법을 배우게 됩니다.
요약
- Spring Batch의 기본 구성 요소에 대한 설정 방법을 설명합니다.
- JobRepository, JobLauncher 등을 등록하는 방법을 배우게 됩니다.
- 배치 Job 및 Step을 정의하고 실행하는 다양한 방법을 배운다.
배경/문제
Spring Batch를 사용하기 위해서는 배치 메타테이블을 관리할 JobRepository, JobLauncher 등을 빈으로 등록해야 합니다. 이에 따라 Job과 Step을 정의하고, 원하는 시점에 배치 Job을 실행하는 코드가 필요합니다.
접근/해결 전략
구성 과정은 크게 세 가지 단계로 나눌 수 있습니다.
- Spring Batch 인프라 설정
- Job 및 Step 정의
- Job 실행 로직 구현
구현 포인트
1) 배치 메타 설정 (Spring Batch 인프라 설정)
아래 예시는 batchDataSource를 사용하고, Spring Batch에서 요구하는 JobRepository, JobLauncher 등을 등록하는 방법입니다.
package syworks.techlab.base.config.batch;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
@Configuration
@EnableBatchProcessing
public class BatchMetaConfig {
@Bean
public JobRepository jobRepository(
@Qualifier("batchDataSource") DataSource batchDataSource,
@Qualifier("batchTransactionManager") PlatformTransactionManager batchTxManager
) throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(batchDataSource);
factory.setTransactionManager(batchTxManager);
factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
factory.setTablePrefix("BATCH_");
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean
public JobBuilderFactory jobBuilderFactory(JobRepository jobRepository) {
return new JobBuilderFactory(jobRepository);
}
@Bean
public StepBuilderFactory stepBuilderFactory(
JobRepository jobRepository,
@Qualifier("batchTransactionManager") PlatformTransactionManager batchTxManager
) {
return new StepBuilderFactory(jobRepository, batchTxManager);
}
}
@EnableBatchProcessing를 사용하면 기본적으로 JobLauncher, JobRepository 등이 자동으로 등록됩니다. 다중 DataSource 환경에서는 수동 구성을 하는 경우가 많습니다.
2) 실제 배치 Job/Step 정의
위에서 만든 JobBuilderFactory, StepBuilderFactory를 사용하여 Job과 Step을 정의합니다.
package syworks.techlab.base.config.batch;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ExampleJobConfig {
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
public ExampleJobConfig(JobBuilderFactory jobBuilderFactory,
StepBuilderFactory stepBuilderFactory) {
this.jobBuilderFactory = jobBuilderFactory;
this.stepBuilderFactory = stepBuilderFactory;
}
@Bean
public Job exampleJob() {
return jobBuilderFactory.get("exampleJob")
.start(exampleStep())
.build();
}
@Bean
public Step exampleStep() {
return stepBuilderFactory.get("exampleStep")
.tasklet((contribution, chunkContext) -> {
System.out.println("Running exampleStep with batchDataSource...");
return RepeatStatus.FINISHED;
})
.build();
}
}
Tasklet을 사용한 단순 예시입니다. Chunk-Oriented 로직도 동일한 원리로 작성 가능합니다.
3) 배치를 실제로 실행하는 방법
배치 Job 실행 시점 및 방법은 운영 정책에 따라 다릅니다.
(a) 애플리케이션 기동 시 자동 실행
CommandLineRunner나 ApplicationRunner를 사용해 앱 시작 시 배치 Job을 한 번 수행합니다.
package syworks.techlab.base.batch.runner;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
import org.springframework.batch.core.launch.JobParametersBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class BatchJobRunner implements CommandLineRunner {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job exampleJob;
@Override
public void run(String... args) throws Exception {
try {
var jobParams = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(exampleJob, jobParams);
} catch (JobExecutionNotRunningException e) {
e.printStackTrace();
}
}
}
(b) 스케줄링
@Scheduled를 사용하여 특정 주기로 Job을 실행합니다.
package syworks.techlab.base.batch.runner;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@Configuration
@EnableScheduling
public class BatchScheduler {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job exampleJob;
@Scheduled(cron = "0 0/5 * * * *")
public void runJob() throws Exception {
var jobParams = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(exampleJob, jobParams);
}
}
(c) REST API
관리자 페이지 같은 곳에서 HTTP 요청을 통해 배치 Job을 트리거할 수 있습니다.
package syworks.techlab.base.batch.api;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/batch")
public class BatchController {
private final JobLauncher jobLauncher;
private final Job exampleJob;
public BatchController(JobLauncher jobLauncher, Job exampleJob) {
this.jobLauncher = jobLauncher;
this.exampleJob = exampleJob;
}
@PostMapping("/example")
public ResponseEntity<String> runExampleJob() {
try {
var jobParams = new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(exampleJob, jobParams);
return ResponseEntity.ok("exampleJob started");
} catch (Exception e) {
return ResponseEntity.badRequest().body("error: " + e.getMessage());
}
}
}
주의사항/트레이드오프
- 배치 Job을 실행할 때 파라미터를 각기 다르게 주어야 중복 실행 오류를 피할 수 있습니다.
- 단일
@Configuration클래스 내에서 모든 설정을 처리할 수 있지만, 규모가 커질 경우 유지보수 측면에서 분리하는 것이 유리합니다.
마무리
- DB 설정(배치 전용 Config)
batchDataSource와batchTransactionManager생성.
- Spring Batch 인프라 설정
@EnableBatchProcessing로 자동 구성 활성화.- 다중 DataSource 환경에서는 수동 설정 필요.
- Job/Step 정의 -