Spring Batch - 15. JobBuilderFactory & JobBuilder

출처

목차

JobBuilderFactory

JobBuilder 객체를 생성하는 팩토리 클래스

  • jobBuilderFactory.get(“jobName”)
    • “jobName” 은 스프링 배치가 Job 을 실행시킬때 참조하는 Job 이름
    • “jobNaem” 은 DB 에도 저장된다.

JobBuilderFactory.java

public class JobBuilderFactory {

private JobRepository jobRepository;

public JobBuilderFactory(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}

public JobBuilder get(String name) {
// JobBuilder 클래스가 생성되는 시점에 JobRepository 객체가 전달된다.
JobBuilder builder = new JobBuilder(name).repository(jobRepository);
return builder;
}
}

JobBuilder

Job 을 구성하는 설정 조건에 따라 두개의 하위 Builder 클래스를 생성하고 실제 Job 생성을 위임 한다.

  • start() 에 Step 객체가 들어가면 SimpleJobBuilder 를 반환한다.

  • start() 에 Flow 객체가 들어가면 FlowJobBuilder 를 반환한다.

  • flow() 에 Step 객체가 들어가면 FlowJobBuilder 를 반환한다.

  • SimpleJobBuilder

    • SimpleJob 을 생성하는 Builder 클래스
  • FlowJobBuilder

    • FlowJob 을 생성하는 Builder 클래스

JobBuilder.java

public class JobBuilder extends JobBuilderHelper<JobBuilder> {

public JobBuilder(String name) {
super(name);
}

// Parameter 가 Step 객체일 경우 SimpleJobBuilder 객체를 반환한다.
public SimpleJobBuilder start(Step step) {
return new SimpleJobBuilder(this).start(step);
}

// Parameter 가 Flow 객체일 경우 JobFlowBuilder 객체를 반환한다.
public JobFlowBuilder start(Flow flow) {
return new FlowJobBuilder(this).start(flow);
}

// Parameter 가 Step 객체일 경우 JobFlowBuilder 객체를 반환한다.
public JobFlowBuilder flow(Step step) {
return new FlowJobBuilder(this).start(step);
}
}

  • JobBuilder 클래스는 JobBuilderHelper 클래스를 상속하고 있다.
  • CommonJobProperties 는 Job 생성에 사용되는 공통 속성을 정의하는 클래스
  • CommonJobProperties 는 JobBuilderFactory에서 사용됩니다.
  • JobBuilderHelper 는 CommonJobProperties 를 참조하고 있다.
  • JobBuilder 클래스는 SimpleJobRepository 클래스를 참조하고 있다.
  • JobRepository 는 Job 이 생성되는 시점, JobBuilder 가 구동되는 시점부터 전달돼 메타 데이터들을 저장하기 위한 초기화 작업을 한다.

JobBuilderHelper

public abstract class JobBuilderHelper<B extends JobBuilderHelper<B>> {

protected final Log logger = LogFactory.getLog(getClass());

private final CommonJobProperties properties;

public JobBuilderHelper(String name) {
this.properties = new CommonJobProperties();
properties.name = name;
}

protected JobBuilderHelper(JobBuilderHelper<?> parent) {
this.properties = new CommonJobProperties(parent.properties);
}

public B validator(JobParametersValidator jobParametersValidator) {
properties.jobParametersValidator = jobParametersValidator;
@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

public B incrementer(JobParametersIncrementer jobParametersIncrementer) {
properties.jobParametersIncrementer = jobParametersIncrementer;
@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

public B repository(JobRepository jobRepository) {
properties.jobRepository = jobRepository;
@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

public B listener(Object listener) {
Set<Method> jobExecutionListenerMethods = new HashSet<>();
jobExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeJob.class));
jobExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterJob.class));

if(jobExecutionListenerMethods.size() > 0) {
JobListenerFactoryBean factory = new JobListenerFactoryBean();
factory.setDelegate(listener);
properties.addJobExecutionListener((JobExecutionListener) factory.getObject());
}

@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

public B listener(JobExecutionListener listener) {
properties.addJobExecutionListener(listener);
@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

public B preventRestart() {
properties.restartable = false;
@SuppressWarnings("unchecked")
B result = (B) this;
return result;
}

protected String getName() {
return properties.name;
}

protected JobRepository getJobRepository() {
return properties.jobRepository;
}

protected boolean isRestartable() {
return properties.restartable;
}

protected void enhance(Job target) {

if (target instanceof AbstractJob) {

AbstractJob job = (AbstractJob) target;
job.setJobRepository(properties.getJobRepository());

// JobParametersIncrementer 설정
JobParametersIncrementer jobParametersIncrementer = properties.getJobParametersIncrementer();
if (jobParametersIncrementer != null) {
job.setJobParametersIncrementer(jobParametersIncrementer);
}

// JobParametersIncrementer 설정
JobParametersValidator jobParametersValidator = properties.getJobParametersValidator();
if (jobParametersValidator != null) {
job.setJobParametersValidator(jobParametersValidator);
}

Boolean restartable = properties.getRestartable();
if (restartable != null) {
job.setRestartable(restartable);
}

List<JobExecutionListener> listeners = properties.getJobExecutionListeners();
if (!listeners.isEmpty()) {
job.setJobExecutionListeners(listeners.toArray(new JobExecutionListener[0]));
}

}

}

public static class CommonJobProperties {

private Set<JobExecutionListener> jobExecutionListeners = new LinkedHashSet<>();

private boolean restartable = true;

private JobRepository jobRepository;

private JobParametersIncrementer jobParametersIncrementer;

private JobParametersValidator jobParametersValidator;

public CommonJobProperties() {
}

public CommonJobProperties(CommonJobProperties properties) {
this.name = properties.name;
this.restartable = properties.restartable;
this.jobRepository = properties.jobRepository;
this.jobExecutionListeners = new LinkedHashSet<>(properties.jobExecutionListeners);
this.jobParametersIncrementer = properties.jobParametersIncrementer;
this.jobParametersValidator = properties.jobParametersValidator;
}

public JobParametersIncrementer getJobParametersIncrementer() {
return jobParametersIncrementer;
}

public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) {
this.jobParametersIncrementer = jobParametersIncrementer;
}

public JobParametersValidator getJobParametersValidator() {
return jobParametersValidator;
}

public void setJobParametersValidator(JobParametersValidator jobParametersValidator) {
this.jobParametersValidator = jobParametersValidator;
}

public JobRepository getJobRepository() {
return jobRepository;
}

public void setJobRepository(JobRepository jobRepository) {
this.jobRepository = jobRepository;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public List<JobExecutionListener> getJobExecutionListeners() {
return new ArrayList<>(jobExecutionListeners);
}

public void addStepExecutionListeners(List<JobExecutionListener> jobExecutionListeners) {
this.jobExecutionListeners.addAll(jobExecutionListeners);
}

public void addJobExecutionListener(JobExecutionListener jobExecutionListener) {
this.jobExecutionListeners.add(jobExecutionListener);
}

public boolean getRestartable() {
return restartable;
}

public void setRestartable(boolean restartable) {
this.restartable = restartable;
}
private String name;
}
}
@Bean
public Job batchJob1() {
return this.jobBuilderFactory.get("batchJob1")
.incrementer(new RunIdIncrementer())
.start(step1())
.next(step2())
.build();
}

@Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.tasklet((contribution, chunkContext) -> {
System.out.println(">> step1 has executed");
return RepeatStatus.FINISHED;
})
.build();
}

@Bean
public Step step2() {
return stepBuilderFactory.get("step2")
.tasklet((contribution, chunkContext) -> {
System.out.println(">> step2 has executed");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public Job batchJob2() {
return this.jobBuilderFactory.get("batchJob1")
.incrementer(new RunIdIncrementer())
.start(flow())
.next(step2())
.end()
.build();
}

@Bean
public Step step2() {
return stepBuilderFactory.get("step2")
.tasklet((contribution, chunkContext) -> {
System.out.println(">> step2 has executed");
return RepeatStatus.FINISHED;
})
.build();
}

@Bean
public Flow flow() {
FlowBuilder<Flow> flowBuilder = new FlowBuilder<>("flow");
flowBuilder.start(step3())
.next(step4())
.end();
return flowBuilder.build();
}
Share