배치 초기화 설정
JobLauncherApplicationRunner
- 스프링 배치 작업을 시작하는 ApplicationRunner로서, BatchAutoConfiguration (Spring Boot 3.3.0 API) 에서 생성됨
- ApplicationRunner의 구현체로, 어플리케이션이 정상적으로 구동되자마자 실행됨
- 기본적으로 빈으로 등록된 모든 job을 실행시킴
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class JobLauncherApplicationRunner implements ApplicationRunner {
private final JobLauncher jobLauncher;
private final Job job;
public JobLauncherApplicationRunner(JobLauncher jobLauncher, Job job) {
this.jobLauncher = jobLauncher;
this.job = job;
}
@Override
public void run(ApplicationArguments args) throws Exception {
jobLauncher.run(job, new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters());
}
}
BatchProperties
- Spring Batch의 환경 설정 클래스
- Job이름, 스키마 초기화 설정, 테이블 prefix등의 값을 설정할 수 있음
# 테이블 이름 접두사 설정
spring.batch.table-prefix=BATCH_
# 어플리케이션 실행시 배치 작업 실행 여부 설정
spring.batch.job.enabled=true
- properties나 yml파일에 설정한다.
Job 실행 옵션
- 지정한 Batch Job만 실행하도록 할 수 있음
=> -ApplicationRunner를 상속받아 설정 가능함.
- program arguments 필드로 Program Arguments 이름 입력함.
@Component
public class JobRunner implements ApplicationRunner {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private ApplicationContext applicationContext;
@Override
public void run(ApplicationArguments args) throws Exception {
if (args.containsOption("jobName")) {
String jobName = args.getOptionValues("jobName").get(0);
Job job = (Job) applicationContext.getBean(jobName);
jobLauncher.run(job, new JobParametersBuilder()
.addLong("time", System.currentTimeMillis())
.toJobParameters());
} else {
System.out.println("No jobName parameter provided. Skipping job execution.");
}
}
}
--jobName=job1
Job and Step
JobBuilderFactory
- JobBuilder를 생성하는 팩토리 클래스
- jobBuilderFactory.get("jobName")
JobBuilder
- job을 구성하는 설정 조건에 따라 하위 빌더 클래스를 생성하고, 실제 Job 생성을 위임함
1. SimpleJobBuilder
=> SimpleJob을 생성하는 Builder 클래스
=> Job 실행과 관련된 여러 설정 API 제공
SimpleJobBuilder (Spring Batch 5.1.2 API)
2. FlowJobBuilder
=> FlowJob을 생성하는 Builder 클래스
=> 내부적으로 FlowBuilder 반환
FlowJobBuilder (Spring Batch 5.1.2 API)
흐름은 대략 다음과 같다.
1. JobBuilderFactory가 get("JobName")으로 JobBuilder를 생성하고
2. JobBuilder가
2-1. start(step) 호출 하면, SimpleJob을 생성하는 SimpleJobBuilder를 만든다.
2-2. start(flow) 호출하면, FlowJob을 생성하는 FlowJobBuilder를 만든다.
2-3. flow(step) 호출하면, FlowJob을 생성하는 FlowJobBuilder를 만든다.
JobBuilderFactory에 대한 상속구조는 다음과 같다.
- JobBuilderFactory -> 주로 JobBuilder를 생성하는 팩토리 클래스 (JobRepository를 필요로 하며, 이를 통해 생성된 Job등록 및 관리함)
- JobBuilderHelper -> 빌더 클래스의 공통 기능을 제공하는 추상 클래스
- JobBuilder -> 기본적인 배치 작업을 구성하는 빌더 클래스
- SimpleJobBuilder -> 기본적인 Step기반의 Job을 구성하는 빌더 클래스
- FlowJobBuilder -> Flow(여러 Step을 논리적으로 묶어 처리하는데 사용)기반의 Job을 구성하는 빌더 클래스
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.batch.core.configuration.annotation;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
public class JobBuilderFactory {
private JobRepository jobRepository;
public JobBuilderFactory(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}
public JobBuilder get(String name) {
JobBuilder builder = (JobBuilder)(new JobBuilder(name)).repository(this.jobRepository);
return builder;
}
}
JobBuilder가 생성되는 시점에, repository가 전달됨.
new JobBuilder(name)를 호출하여 JobBuilder 인스턴스를 생성하고, repository(jobRepository)를 호출하여 JobRepository를 설정함.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.batch.core.job.builder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.Flow;
public class JobBuilder extends JobBuilderHelper<JobBuilder> {
public JobBuilder(String name) {
super(name);
}
public SimpleJobBuilder start(Step step) {
return (new SimpleJobBuilder(this)).start(step);
}
public JobFlowBuilder start(Flow flow) {
return (new FlowJobBuilder(this)).start(flow);
}
public JobFlowBuilder flow(Step step) {
return (new FlowJobBuilder(this)).start(step);
}
}
- 위의 start(), flow()등의 흐름을 알 수 있음
public class SimpleJobBuilder extends JobBuilderHelper<SimpleJobBuilder> {
private List<Step> steps = new ArrayList();
private JobFlowBuilder builder;
public SimpleJobBuilder(JobBuilderHelper<?> parent) {
super(parent);
}
public Job build() {
if (this.builder != null) {
return ((FlowJobBuilder)this.builder.end()).build();
} else {
SimpleJob job = new SimpleJob(this.getName());
super.enhance(job);
job.setSteps(this.steps);
try {
job.afterPropertiesSet();
return job;
} catch (Exception var3) {
throw new JobBuilderException(var3);
}
}
}
- 기본적인 Step기반의 Job을 구성하는 빌더 클래스
- 필드로 Job에 포함될 Step들의 리스트를 지님
- build시 job을 생성하고, step을 설정하는 것을 알 수 있음.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.batch.core.job.builder;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowJob;
import org.springframework.batch.core.step.builder.StepBuilderException;
public class FlowJobBuilder extends JobBuilderHelper<FlowJobBuilder> {
private Flow flow;
public FlowJobBuilder(JobBuilderHelper<?> parent) {
super(parent);
}
public JobFlowBuilder start(Flow flow) {
return new JobFlowBuilder(this, flow);
}
public JobFlowBuilder start(Step step) {
return new JobFlowBuilder(this, step);
}
protected FlowJobBuilder flow(Flow flow) {
this.flow = flow;
return this;
}
public Job build() {
FlowJob job = new FlowJob();
job.setName(this.getName());
job.setFlow(this.flow);
super.enhance(job);
try {
job.afterPropertiesSet();
return job;
} catch (Exception var3) {
throw new StepBuilderException(var3);
}
}
}
SimpleJob
- Step을 실행시키는 Job의 구현체로서, SimpleJobBuilder에 의해 생성됨
- 여러 단계의 Step으로 구성할 수 있으며, Step을 순차적으로 실행시킴
- 모든 Step의 실행이 성공이 성공적으로 완료되어야, Job이 성공적으로 완료된다.
public Job batchJob() {
return jobBuilderFactory.get("batchJob") // JobBuilder를 생성하는 팩토리로, Job의 이름을 매개변수로 받음
.start(Step) // 처음 실행할 Step 설정, 최초 한 번 설정, 이 메서드를 실행하면 SimpleJobBuilder를 반환함
.next(Step) // 다음 실행할 Step 설정
.incrementer(jobParametersIncrementer) // JobParameter의 값 자동 증가
.preventRestart(true) // Job의 재 시작 가능 여부 설정, 기본 값은 true
.validator(JobParamterValidator) // 올바른 구성이 되었는지 검증하는 JobParametersValidator설정
.listener(JobExcecutionListener) // Job라이프 사이클 특정 시점에 콜백함수 설정하는 JobExcecutionListener 설정
.build(); // SimpleJob생성
}
validator()
- job실행에 꼭 필요한 파라미터를 검증하는 용도
- DefaultJobParametersValidator 구현체를 지원함. 좀 더 복잡한 제약 조건이 있다면 인터페이스를 직접 구현할 수도 있음
preventRestart()
- Job의 재 시작 여부를 설정
- 기본 값은 true이고 false로 설정시, 이 Job은 재 시작을 지원하지 않는다는 의미
- Job이 실패해도 재 시작이 안됨 => Job을 재시작하려고하면 JobRestartException이 발생함
incrementer()
- JobParameters에서 필요한 값을 증가시켜 다음에 사용될 JobParameters 오브젝트를 리턴
- 기존의 JobParameter 변경 없이 Job을 여러 번 시작하고자 할 때
SimpleJob 실행 흐름
- JobLauncher에 의해 JobExecution이 생성됨
- JobExcecutionListener에 의해 beforeJob메서드가 호출됨
- 등록된 step들을 순차적으로 실햄함
1. StepExcecution 생성
2. StepExcecutionLister의 berforeJob 호출
3. Step이 순차적으로 실행됨
4. JobExcecutionLister의 afterJob이 호출됨
5. 마지막으로 작업상태를 마지막 Step단계와 동일하게 업데이트함.
StepBuilderFactory
- StepBuilder를 생성하는 팩토리 클래스, get(String name) 메서드 제공
- 여기서 Step은 Spring Batch Job의 기본 구성 요소로, 실제 배치 처리 로직이 포함된 단위를 나타냄.
- StepBuilderFactory.get("stepName")
=> "stepName"으로 Step을 생성
StepBuilder
- Step을 구성하는 설정 조건에 따라 다섯 개의 하위 빌더 클래스를 생성하고 실제 Step생성을 위임
- TaskletStepBuilder
=> TaskletStep을 생성하는 기본 빌더 클래스
@Bean
public Step step1() {
return stepBuilderFactory.get("taskletStep")
.tasklet((contribution, chunkContext) -> {
return RepeatStatus.FINISHED;
})
.build();
}
- SimpleStepBuilder
=> TaskletStep을 생성하며 내부적으로 청크기반의 작업을 처리하는 ChunkOrientedTasklet클래스를 생성한다.
stepBuilderFactory.get("simpleStep")
.<String, String>chunk(10)
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.build();
- PartitionStepBuilder
=> PartitionStep을 생성하며 멀티 스레드 방식으로 Job을 생성함
stepBuilderFactory.get("partitionStep")
.partitioner("slaveStep", partitioner())
.step(slaveStep())
.gridSize(10)
.taskExecutor(taskExecutor())
.build();
- JobStepBuilder
=> JobStep을 생성하며, Step안에서 Job을 실행함
stepBuilderFactory.get("jobStep")
.job(job())
.parametersExtractor(jobParametersExtractor())
.build();
- FlowStepBuilder
=> FlowStep을 생성하여 Step안에서 Flow를 실행함.
stepBuilderFactory.get("flowStep")
.flow(flow())
.build();
TaskletStep
- Tasklet을 실행시키는 도메인 객체
- RepeatTemplate 사용하여, Tasklet의 구문을 트랜잭션 경계 내에서 반복해서 실행함
- Task기반과 Chunk 기반으로 나누어서 Tasklet을 실행함
Task vs Chunk기반 비교
- 스프링 배치에서 Step의 실행 단위는 크게 2가지로 나뉘어짐
chunk 기반
- 하나의 큰 덩어리를 n개씩 나눠서 실행한다는 의미 => 대량 처리로 인해 효과적으로 설계됨
- ItemReader, ItemProcessor, ItemWriter를 사용하여 청크 기반 전용 Tasklet인 ChunkOrientedTasklet구현체가 제공됨.
public Step step() {
return this.stepBuilderFactory.get("step")
.<String, String>chunk(100)
.reader()
.writer()
.build();
}
Task 기반
- 주로 Tasklet구현체를 만들어 사용한다.
- 대량 처리를 하는 경우 chunk보다 더 복잡한 구현이 필요하다.
public Step step() {
return this.stepBuilderFactory.get("step")
.tasklet(myTasklet())
.build();
}
public Step batchStep() {
return stepBuilderFactory.get(“batchStep") // stepBuilder를 생성하는 팩토리, Step이름을 매개 변수로 받음
.tasklet(Tasklet) // Tasklet 클래스 설정, 이 메서드를 실행하면 TaskletStepBuilder 반환
.startLimit(10) // Step의 실행횟수를 설정
.allowStartIfComplete(true) // Step의 성공, 실패와 상관 없이 항상 Step을 실행하기 위한 설정
.listener(StepExecutionListener) // Step라이프 사이클의 특정 시점에 콜백 제공받도록 StepExcecutionListener 설정
.build(); // Tasklet을 생성
}
Tasklet()
- Tasklet 타입의 클래스를 설정한다
- Tasklet :
- Step내에서 구성되고 실행되는 도메인 객체로, 단일 태스크를 수행하기 위한 것
- TaskletStep에 의해 반복적으로 수행되며, 반환값에 따라 계속 수행 혹은 종료함
- RepeatStatus - Tasklet의 반복 여부 상태 값
=> RepeatStatus.FINSIHED => Tasklet 종료 / 리턴되거나 실패 예외가 던져질때까지 while문 안에서 반복적으로 호출
=> RepeatStatus.CONTINUABLE => Tasklet 반복
- 익명 클래스 혹은 구현 클래스 만들어서 사용한다.
- Step에 오직 하나의 Tasklet 설정이 가능함.
startLimit()
- step 설정시 사용하는 메서드
- step의 실행횟수를 조정할 수 있다.
- Step마다 설정할 수 있다
- 설정 값을 초과해서 다시 실행하면, startLimitExceededException이 발생함
- start-limit의 디폴트 값은 Integer.MAX_VALUE
allowStartIfComplete()
- step 설정시 사용하는 메서드
- 재시작 가능한 job에서 Step의 이전 성공여부와 상관없이 항상 step을 실행하기 위한 설정
- true로 설정하게 되면 step은 항상 실행함
- ex) 사전 작업이 꼭 필요한 step
TaskletStep 아키텍쳐
JobStep
- job에 속하는 step중 외부의 Job을 포함하고 있는 Step
- 외부의 Job이 실패하면 해당 Step이 실패하므로 결국 최종 기본 Job도 실패함
pulbic Step jobStep() {
return stepBuilderFactory.get("jobStep")
.job(Job)
.launcher(JobLauncher)
.parametersExtractor(JobParametersExtractor)
.build();
}
+)
[Batch] Spring Batch 5 적용 | For My Developer (europani.github.io)
배치 5버전 사용시 기존 내용과 많이 다른 듯하다.
출처 ) 인프런 스프링 배치 강의
'Spring' 카테고리의 다른 글
Spring Batch - Chunk (0) | 2024.06.22 |
---|---|
Spring Batch - Flow (0) | 2024.06.15 |
Spring Batch - 개요, 도메인 이해 (0) | 2024.05.26 |
Spring AOP vs AspectJ (0) | 2023.11.21 |
Weaving (0) | 2023.11.21 |