✅ Scope(스코프)란??
- 스프링 컨테이너에서 스코프란, 빈의 생명주기와 접근 범위를 정의하는 개념이다
- 종류로는 singleton, prototype, request. session 등이 있으며,
- 스프링에서 빈은 기본적으로 singleton으로 생성된다.
✅ 배치 Scope
기본 개념
배치를 처리하다보면 동적으로 값을 주입받아야 하는 경우가 많다.
스프링 배치는 동적으로 값을 받아 빈을 생성시키기 위해 커스텀 스코프를 제공해주는데 대표적인 2가지가 아래와 같다.
- @JopScope
- @StepScope
💡 이 기능을 쓰면 좋은 점 미리 알기 (뒤에서 또 언급)
- 단순히 동적 주입만이 장점이 아니다
- 좋은 점은 스레드 안정성이 있다는 것이다.
- 빈이 늦게 생성되어서 성능이 부담된다고 느낄 수 있지만, 재사용성-동적-스레드 안정성의 장점 때문에 습관적으로 @~Scope를 쓰는 것 같다.
그림 이해
이 애노테이션이 붙은 빈은 프록시 모드로 선언되어 내부적으로 Proxy객체가 생성된다.
애플리케이션 구동시점에는 프록시 객체가 생성되고, 실제 이 빈이 실행되는 시점에 실제 빈을 호출한다.
큰 장점으로는, 병렬 처리 시 각 스레드마다 생성된 스코프 빈이 할당되기 때문에 스레드에 안전하게 실행이 가능하다.
아래로 가면 더 자세한 그림이 나오니 그거 확인할 것
1. @JobScope
✅ 개념
- Job 실행 시점마다 빈이 생성된다.
- 사용 가능한 곳 : step 선언문에만 정의가 가능하다.
- 🚨 즉, Tasklet, Reader, Processor, Writer 등에는 붙이지 않는다.
- @Value 활용하면
- JobParameter 또는 JobExecutionContext 값을 주입 받을 수 있다
- 이를 통해 동적 주입이 가능한 것이다.
@Bean("s3BackupStep") @JobScope public Step s3BackupStep( @Value("#{jobParameters['backupDateTime']}") LocalDateTime toBackupDateTime)
2. @StepScope
✅ 개념
- Step 실행 시점마다 빈이 생성된다.
- 1번의 경우와 달리 JobParameter, JobExecutionContext, StepExecutionContext까지 주입 가능
- 사용 가능한 곳 : Tasklet, ItemReader, ItemProcessor, ItemWriter에 사용
- @Value를 활용하면
- 1번의 경우와 마찬가지로 JobParameter 또는 JobExecutionContext 값을 주입 받을 수 있다
- 또한, @StepScope는 stepExecutionContext의 값도 주입 받을 수 있따.
@Bean("s3BackupStep") @StepScope public ItemWriter<? ?>s3BackupItemWriter( @Value("#{jobParameters['backupDateTime']}") LocalDateTime toBackupDateTime)
아키텍쳐(동작 원리)
Proxy가 어떻게 호출을 할까?
❓@StepScope, @JobScope가 붙은 빈은 Proxy객체로 생성될텐데 어떤 원리로 실제 객체를 불러올까❓
사실, 실제 빈의 위치는 JobContext, StepContext에 있다!!
JobContext, StepContext
- 스프링 컨테이너에서 생성된 빈을 저장하는 컨텍스트 역할
- Job,StepContext가 필요한 빈들만 저장하고 있음
- 즉, Proxy빈이 실제 참조할 때 활용됨
- 실제 빈 참조시 ApplicationContext가 아닌 Job(Step)Context를 부르는 것
- JobContext → Job 실행 중 동적으로 생성된 Bean을 저장/관리
- StepContext → Step 실행 중 동적으로 생성된 Bean을 저장/관리
그림으로 이해하기
- Job이 Proxy객체인 Step을 호출
- JobScope클래스는 내부적으로 JobContext 속성을 가지고 있다.
- 이를 통해 Proxy객체가 참조할 빈을 JobScope에게 요청하면 JobScope는 자신이 갖고 있는 JobContext속성을 참고하여 실제 빈을 찾음
✅ 런타임 시점에 빈 생성 + @Valid 바인딩 (그림 참고)
- @JobScope를 붙인 step은 애플리케이션 구동 시점에는 빈이 없기 떄문에 호출 당하면, BeanFactory에서 빈을 생성해준다.
- 이 생성 시점에!!! @Value 바인딩처리가 이루어짐
- 따라서, @Job(step)Scope없이 @Value를 쓰면 오류가 나는 이유가 이것때문이다.
활용하기 좋은 경우 (장점)
❓ 언제 이 Scope를 사용하면 좋을까❓
- @Value나 JobParameter를 통해 외부 파라미터를 주입 받아야 할 때
- ex. Job 실행마다 다른 파라미터를 동적으로 처리하고 싶을 때
- 병렬로 실행되는 Step들에서 각각 다른 상태를 가지는 Bean을 생성하고 싶을 때
번외 : 실제 구현된 거 살펴보기
맛보기 - 기본구조
@JobScope의 기본 구조를 보자
/**
* <p>
* Convenient annotation for **job-scoped beans that defaults the proxy mode**, so that it
* does not have to be specified explicitly on every bean definition. **Use this on any
* @Bean that needs to inject @Values from** the job context, and any bean that
* needs to share a lifecycle with a job execution (such as an JobExecutionListener). The
* following listing shows an example:
* Marking a @Bean as @JobScope is equivalent to marking it as
* <code>@Scope(value="job", proxyMode=TARGET_CLASS)</code>
*/
@Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JobScope {
주석 해석
- 프록시 모드로 되는 것
- 동적 주입이 가능하다는 것
- 사용해라 → @Value로 ~~ 어떤걸 할 떄??
다음은 @StepScope의 기본구조
/**
* <p>
* Convenient annotation for step-scoped beans. It defaults the proxy mode so that it need
* not be specified explicitly on every bean definition. Use this on any @Bean that
* needs to inject @Values from the step context and on any bean that needs to share a
* lifecycle with a step execution (such as an ItemStream). The following listing shows an
* example:
* </p>
*
* <pre class="code">
* @Bean
* @StepScope
* protected Callable<String> value(@Value("#{stepExecution.stepName}")
* final String value) {
* return new SimpleCallable(value);
*/
@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StepScope
'백엔드 > 스프링' 카테고리의 다른 글
프로메테우스, 그라파나, 애플리케이션 - 도커로 설치 및 연동 (1) | 2025.05.01 |
---|---|
Spring Batch : 서로 다른 Step 끼리 데이터 공유하기 (0) | 2025.04.27 |
S3Resource사용 : 순환참조 오류 (0) | 2025.04.23 |
Spring-batch 테스트 : 여러 JOB에서 생기는 오류 NoUniqueBeanDefinitionException (0) | 2025.04.22 |
@Value vs @ConfigurationProperties (0) | 2025.04.13 |