개발공부/SPRING

[Spring Batch] @JobScope, @StepScope

키크니개발자 2023. 6. 6. 10:19

@JobScope, @StepScope

Scope

  • 스프링 컨테이너에서 빈이 관리되는 범위를 의미한다.
  • singleton, prototype, request, session, application

 

공통점

  • Job과 Step의 빈 생성과 실행에 관여하는 스코프이다.
  • 프록시 모드가 기본 값 : @Scope(value="job", proxyMode=ScopedProxyMode.TARGET_CLASS)
  • 해당 스코프가 선언되면 빈 생성 시점이 어플리케이션 구동 시점이 아니라 빈의 실행 시점에 이뤄진다. → 프록시 객체가 실제 빈을 호출해서 메소드 실행한다.
  • 병렬처리 시 각 쓰레드마다 스코프 빈이 할당되기 때문에 안전하다.

 

@JobScope

  • Step 선언문에 정의한다.
  • @Value: jobParameter, jobExecutionContext 만 사용 가능 → jobExecutionListener 에서 값을 가져올 수 있다.

 

@StepScop

  • Tasklet이나 ItemReader, ItemWriter, ItemProcessor 선언문에 정의한다.
  • @Value: jobParameter, jobExecutionContext, stepExecutionContext 사용 가능 → stepExecutionListener 에서 값을 가져올 수 있다.
    • @Value(”#{jobParamters[파라미터명]}”)
    • @Value(”#{jobExecutionContext[파라미터명]}”)
    • @Value(”#{stepExecutionContext[파라미터명]}”)

 

JopScope, StepScope 클래스

  • Proxy 객체의 실제 대상이 되는 Bean을 등록, 해제하는 역할을 한다.
  • 실제 빈을 저장하고 있는 JobContext, StepContext를 가지고 있다. → Spring의 ApplicationContext와 비슷 application.getBean(”name”, type)을 통해서 빈을 얻듯이 비슷하다.
    • jobContext → Job의 범위를 가지고 있는 Step 빈을 얻는다.
    • stepContext → Step의 범위를 가지고 있는 Tasklet, Reader, Wrtiter, Processor 빈을 얻는다.

 

JobContext, StepContext 클래스

  • 스프링 컨테이너에서 생성된 빈(job, step scope의 빈)을 저장하는 컨텍스트 역할을 한다.
  • 스프링 배치에서 해당 프록시 객체의 타켓이 되는 실제 빈을 참조할 땐 ApplicationContext에서 빈을 찾는게 아니다.
@Bean
public Job simpleJob() {
	return this.jobBuilderFactory.get("simpleJob")
					.start(step1(null))
					.next(step2())
					.build();
}

@Bean
@JobScope
public Step step1(@Value("#{jobParamter[date]}") String requestDate) {
	return this.stepBuilderFactory.get("step1")
					.tasklet(aTasklet())
					.build()
}

@Bean
@StepScop
public Tasklet aTasklet() {
	return new ATasklet();
}

 

스프링 배치 실행 흐름

1. 어플리케이션 구동이 되면 ApplicationContext가 어플리케이션에 정의한 Bean이 생성한다.

  • 생성 중에 @JobScope가 붙었는지를 확인한다.
    • 없다면 Singleton bean으로 생성 (@Value 사용시에 오류)
    • 있다면 Proxy 객체로 생성 (TaskletStep, FlowStep 등이 실제 객체)

 

2. 스프링이 초기화가 완료되고 스프링 부트가 JobLauncher를 통해서 Job이 실행한다. (jobLauncher.run())

  • 이때 Job은 여러 개의 Step을 가지고 있을 텐데 실제 Step이 아닌 내부적으로 Proxy 객체를 가지고 있고 해당 Proxy 객체를 호출한다.
  • 그리고 Proxy 객체는 Step의 메소드 호출 시 실제 Bean 객체를 참조하는데 이 시점에 Step의 빈이 생성된다. → 스프링 구동 시점에 Step 빈이 생성이 되는 것이 아니라 실행 시점에 해당 Bean이 생성 
    • 여기서 Proxy 객체는 어떻게 참조할 실제 Bean을 구하는가?
      • JobScope 클래스를 참조한다. → 구동 시점에 등록된 빈이다.
      • JobScope 클래스의 역할은 Proxy 객체의 대상이 되는 실제 Bean을 JobContext에서 꺼내서 등록(혹은 해제)하는데JobContext에 실제 Bean이 있다면 꺼내서 Proxy 객체와 연결한다. → 그리고 실제 Step 실행한다.
      • 없다면 스프링의 BeanFactory를 통해서 실제 Step의 빈을 생성하는데 이 시점에 우리가 정의한 Step 메소드를 호출해서 빈을 생성하고, @Value 어노테이션의 바인딩이 이뤄진다. → 그리고 JobContext에 만든 빈을 등록한다.

 

3. Tasklet, Reader, Processor, Writer의 경우도 @StepScope이 붙어있기 때문에 프록시 객체로 생성되고 이후 실제 빈을 생성하는 것은 Step의 실제 대상이 되는 객체를 참조하는 것과 비슷한 과정을 거침

반응형