출처
목차
ExecutionContext
프레잌워크에서 유지 및 관리하는 Key/Value 컬렉션으로 JobExecution, StepExecution 객체의 상태를 저장하는 공유 객체
DB 에 직렬화 한 값으로 저장된다.
Job 재 시작시 이미 처리한 Row 데이터는 건너뛰고 이후로 수행하도록 할 때 상태 정보를 활용한다.
ExecutionContext 는 Job 또는 Step 의 실행 중에 데이터를 공유하거나 저장하기 위한 메커니즘으로 JobExecution, StepExecution 및 JobParameter 와 함께 사용됩니다.
ExecutionContext 는 JobExecutionContext 와 StepExecutionContext 로 구분됩니다. JobExecutionContext 는 Job 의 실행 컨텍스트를 나타내며, StepExecutionContext 는 Step 의 실행 컨텍스트를 나타냅니다. JobExecutionContext 는 모든 Step에서 공유됩니다. 그러나 StepExecutionContext 는 Step 간에 공유되지 않으며, 각 Step 에서 고유한 ExecutionContext 를 유지합니다.
ExecutionContext 는 기본적으로 Map<String, Object> 타입으로 사용자가 직접 데이터를 추가, 수정, 삭제할 수 있습니다. 예를 들어, Job 또는 Step 실행 중에 사용자 데이터를 저장하고 싶은 경우, ExecutionContext 를 사용하여 저장할 수 있습니다.
Spring Batch에서 ExecutionContext 를 사용하면 다음 Step 에서 이전 Step 에서 처리된 데이터를 전달하거나 Job 에서 여러 Step 에서 공유하는 데이터를 전달할 수 있습니다. ExecutionContext 를 사용하여 Job 또는 Step 간 데이터 공유를 효율적으로 관리할 수 있습니다.
ExecutionContext 공유 범위
JobExecutionContext 범위
각 Job 의 JobExecution 에 저장되며 Job 간 서로 공유가 안되며 해당 Job 의 Step 간 서로 공유가 가능하다.
StepExecutionContext 범위
각 Step 의 StepExecution 에 저장되며 Step 간 서로 공유가 안된다.
@RequiredArgsConstructor @Configuration public class ExecutionContextConfiguration { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; private final ExecutionContextTasklet1 executionContextTasklet1; private final ExecutionContextTasklet2 executionContextTasklet2; private final ExecutionContextTasklet3 executionContextTasklet3; private final ExecutionContextTasklet4 executionContextTasklet4; @Bean public Job BatchJob () { return this .jobBuilderFactory.get("Job" ) .start(step1()) .next(step2()) .next(step3()) .next(step4()) .build(); } @Bean public Step step1 () { return stepBuilderFactory.get("step1" ) .tasklet(executionContextTasklet1) .build(); } @Bean public Step step2 () { return stepBuilderFactory.get("step2" ) .tasklet(executionContextTasklet2) .build(); } @Bean public Step step3 () { return stepBuilderFactory.get("step3" ) .tasklet(executionContextTasklet3) .build(); } @Bean public Step step4 () { return stepBuilderFactory.get("step4" ) .tasklet(executionContextTasklet4) .build(); } }
@Component public class ExecutionContextTasklet1 implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = contribution.getStepExecution().getJobExecution().getExecutionContext(); ExecutionContext stepExecutionContext = contribution.getStepExecution().getExecutionContext(); String jobName = chunkContext.getStepContext().getStepExecution().getJobExecution().getJobInstance().getJobName(); String stepName = chunkContext.getStepContext().getStepExecution().getStepName(); if (jobExecutionContext.get("jobName" ) == null ){ jobExecutionContext.put("jobName" , jobName); } if (stepExecutionContext.get("stepName" ) == null ) { stepExecutionContext.put("stepName" , stepName); } System.out.println("jobName: " + jobExecutionContext.get("jobName" )); System.out.println("stepName: " + stepExecutionContext.get("stepName" )); return RepeatStatus.FINISHED; } }
@Component public class ExecutionContextTasklet2 implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext(); ExecutionContext stepExecutionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext(); System.out.println("jobName: " + jobExecutionContext.get("jobName" )); System.out.println("stepName: " + stepExecutionContext.get("stepName" )); String stepName = chunkContext.getStepContext().getStepExecution().getStepName(); if (stepExecutionContext.get("stepName" ) == null ) { stepExecutionContext.put("stepName" , stepName); } return RepeatStatus.FINISHED; } }
@Component public class ExecutionContextTasklet3 implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { Object name = chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name" ); if (name == null ){ chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("name" , "user1" ); throw new RuntimeException ("step has failed" ); } return RepeatStatus.FINISHED; } }
@Component public class ExecutionContextTasklet4 implements Tasklet { @Override public RepeatStatus execute (StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("name: " + chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().get("name" )); return RepeatStatus.FINISHED; } }