๐ Spring Batch @JobScope, @StepScope
์ง๋ ํฌ์คํ ์์๋ JobParametersValidator์ ๋ํด ์ดํด๋ณด์๋๋ฐ์ ๊ฐ๋ตํ ์ ๋ฆฌํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Job ์คํ ์ ํ์์ ์ธ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฒ์ฆํ๋ ์ญํ ์ ๋๋ค.
- ๊ธฐ๋ณธ์ ์ผ๋ก DefaultJobParametersValidator ๊ตฌํ์ฒด๋ฅผ ์ง์ํ๋ฉฐ, JobParametersValidator ์ธํฐํ์ด์ค๋ฅผ ์ง์ ๊ตฌํํ์ฌ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฒ์ฆํ ์๋ ์์ต๋๋ค.
์ด๋ฒ์ ์ ๋ฆฌํ @JobScope, @StepScope๋ ์ง๋ Spring Batch Job ํฌ์คํ ์์ JobParameters๋ฅผ ๋ฐ์ ๋ ๊ฐ๋ตํ ์ฌ์ฉ์ ํ์์ต๋๋ค.
- ์ฝ๋๋ก ์์ฑ : JobParameterBuilder
- SPEL ์ฌ์ฉ : @Value(“#{jobParameter[requestDate]}”) - @JobScope, @StepScope ์ ์ธ์ด ํ์
- @JobScope, @StepScope๋ Job, Step์ด ์คํ๋๋ ์์ ์ Bean์ด ์์ฑ๋๋๋ก Bean์ ์์ฑ์์ ์ ์ง์ฐ์ํค๋ ์ญํ ์ ํฉ๋๋ค. @Value ์ด๋ ธํ ์ด์ ์ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋ ๋ ๋ฐ์ธ๋ฉ์ ํ๊ธฐ ๋๋ฌธ์ @JobScope, @Stepcope ์ด๋ ธํ ์ด์ ์ด ์กด์ฌํ์ง ์์ผ๋ฉด NullPointerException ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ด๋ฒ ํฌ์คํ ์์๋ ์กฐ๊ธ ๋ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๐ ๊ธฐ๋ณธ ๊ฐ๋ ๋ฐ ํ๋ผ๋ฏธํฐ ์ค์
1. Scope
- Scope๋ ์คํ๋ง ์ปจํ ์ด๋์์ Bean์ด ๊ด๋ฆฌ๋๋ ๋ฒ์๋ฅผ ๋ปํฉ๋๋ค.
- ์ข
๋ฅ๋ singleton(default), prototype, request, session, application์ด ์กด์ฌํฉ๋๋ค.
- ๊ฐ ์ข ๋ฅ๋ Bean ์ ์์ ๋ํด ์คํ๋ง ์ปจํ ์ด๋ ๋ด์ ๋จ ํ๋๋ง ์กด์ฌํ๋์ง(singleton), ๋ค์๊ฐ ์กด์ฌํ๋์ง(prototype), ๋ผ์ดํ ์ฌ์ดํด์ด Http Request์ธ์ง ๋ฑ์ ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
- ์์ธํ ๋ด์ฉ์ ํด๋น ํฌ์คํ ์ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
2. Spring Batch Scope (@JobScope, @StepScope)
- Spring Batch Scope๋ Job, Step์ Bean ์์ฑ ๋ฐ ์คํ์ ๊ด์ฌํ๋ Scope์ ๋๋ค.
- ํ๋ก์ ๋ชจ๋๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๊ฐ์ง๋ Scope ์ ๋๋ค.
- ํด๋น ์ค์ฝํ๊ฐ ์ ์ธ๋๋ฉด ๋น์ ์์ฑ์ด ์ ํ๋ฆฌ์ผ์ด์
๊ตฌ๋ ์์ ์ด ์๋ Bean์ ์คํ ์์ ์ ์ด๋ฃจ์ด์ง๋๋ค(Lazy Binding)
- ์ฆ Job, Step์ด ์คํ๋๋ ์์ ์ Bean์ด ์์ฑ๋๋๋ฐ์, ์ด๋ @Value ์ด๋ ธํ ์ด์ ์ ๊ฒฝ์ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋ ๋ ๋ฐ์ธ๋ฉ์ ํ๊ธฐ ๋๋ฌธ์ Scope๋ฅผ ํตํด ์์ฑ์์ ์ ์ง์ฐ์์ผ ๋ฐ์ธ๋ฉ์ด ์ด๋ฃจ์ด์ง๋๋ค.
- ์๋์ฒ๋ผ SpEL ํ๊ธฐ๋ฒ์ผ๋ก ์ ์ธํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@Value("#{jobParameters[ํ๋ผ๋ฏธํฐ๋ช ]}") , @Value("#{jobExecutionContext[ํ๋ผ๋ฏธํฐ๋ช ]}")
- ํ๋ก์ ๋ชจ๋๋ก Bean์ด ์ ์ธ๋๊ธฐ ๋๋ฌธ์ ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ๋ ์์ ์๋ Bean์ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ , ๋ฉ์๋ ์คํ ์์ ์์ ์ค์ ๋น์ ํธ์ถํฉ๋๋ค. (AOP)
- ๋ณ๋ ฌ์ฒ๋ฆฌ ์ ๊ฐ ์ค๋ ๋๋ง๋ค ์์ฑ๋ ์ค์ฝํ ๋น์ด ํ ๋น๋๊ธฐ์ Thread-safeํ๊ฒ ์คํ์ด ๊ฐ๋ฅํฉ๋๋ค.
3. @JobScope
- Step ์ ์ธ๋ฌธ์ ์ ์ํฉ๋๋ค.
- @Value: jobParameter, jobExecutionContext๋ง ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
4. @StepScope
- Tasklet์ด๋ ItemReader, ItemWriter, ItemProcessor ์ ์ธ๋ฌธ์ ์ ์ํฉ๋๋ค.
- @Value: jobParameter, stepExecutionContext ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
๐ ์์ ์ฝ๋
Step์๋ @JobScope ์ ์ธ๊ณผ @Value(jobParameters)๋ฅผ ์ ์ธํ์๊ณ , Tasklet์๋ @StepScope์ @Value(jobExecutionContext)๋ฅผ ์ ์ธํด ์ฃผ์์ต๋๋ค.
jobParameters๋ ์คํํ ๋ ์ธ์๋ก ๊ฐ์ ์ฃผ์ ํ์ฌ ๋ฐ๊ณ , jobExecutionContext๋ ์๋ ์ฌ์ง์ฒ๋ผ ์ปค์คํ Listener ํ์ผ์ ์์ฑํ์ฌ ๊ฐ์ ์ค์ ํ๊ฒ ์ต๋๋ค.
JobListener ํด๋์ค๋ฅผ ํ๋ ์์ฑํ์ฌ JobExecutionListener ํด๋์ค๋ฅผ ๊ตฌํํ๊ณ , ์ก์ ์คํํ๊ธฐ ์ (beforeJob) jobExecutionContext์ "name" : "Lee" ์ ๊ฐ์ put ํฉ๋๋ค.
ํ๋ก๊ทธ๋จ ์คํ ์ธ์(Program Arguments): --job.name=scopeJob message="JuHyuns"
๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด๋ฉด ๊ธฐ์กด์ ์ค์ ํ ๊ฐ๋ค์ด ์ ์์ ์ผ๋ก ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
๋ง์ฝ @JobScope๋ฅผ ์ฃผ์ ์ฒ๋ฆฌํ๊ณ ์คํํด ๋ณด๋ฉด JobParameters๊ฐ ์์ฑ๋์ง ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๐ ์ํคํ ์ฒ
1. Proxy ๊ฐ์ฒด ์์ฑ
- @JobScope, @StepScope ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋๋ฉด ๋ด๋ถ์ ์ผ๋ก Bean์ Proxy ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค.
- ์ฆ, Job ์คํ ์ Proxy ๊ฐ์ฒด๊ฐ ์ค์ ๋น์ ํธ์ถํด์ ํด๋น ๋ฉ์๋๋ฅผ ์คํ์ํค๋ ๊ตฌ์กฐ์ ๋๋ค.
2. JobScope, StepScope
- Proxy ๊ฐ์ฒด์ ์ค์ ๋์์ด ๋๋ ๋น์ ๋ฑ๋กํ๊ณ ํด์ ํ๋ ์ญํ ์ ํฉ๋๋ค.
- ์ค์ ๋น์ ์ ์ฅํ๊ณ ์๋ JobContext, StepContext๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
3. JobContext, StepContext
- ์คํ๋ง ์ปจํ ์ด๋์์ ์์ฑ๋ ๋น์ ์ ์ฅํ๋ ์ปจํ ์คํธ ์ญํ ์ ํฉ๋๋ค.
- Job์ ์คํ ์์ ์์ Proxy ๊ฐ์ฒด๊ฐ ์ค์ ๋น์ ์ฐธ์กฐํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
4. ์คํ๋ง ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ๋ ~ @Value ๋ฐ์ธ๋ฉ์ด ์ฒ๋ฆฌ๋๊ธฐ๊น์ง์ ๊ณผ์
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ตฌ๋๋๋ฉด ์คํ๋ง์ ApplicationContext๊ฐ Bean์ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ์ญํ ์ ํฉ๋๋ค.
- @JobScope (ํน์ @StepScope) ์ด๋
ธํ
์ด์
์ด ์กด์ฌํ๋์ง ํ์ธํฉ๋๋ค.
- ์กด์ฌํ์ง ์๋๋ค๋ฉด ๊ธฐ๋ณธ์ ์ธ ์ฑ๊ธํค Bean์ ์์ฑํ๊ณ , @Value ์ด๋ ธํ ์ด์ ์ ์ธ ์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์กด์ฌํ๋ค๋ฉด ํด๋น Bean์ Proxy ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
- @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
- ์ค์ ์ด ๋๋๋ฉด ์คํ๋ง ์ด๊ธฐํ๊ฐ ์๋ฃ๋๊ณ Job์ ์คํํฉ๋๋ค. (JobLauncher)
- Job์ Step์ ์ค์ Bean์ด ์๋ Proxy ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ ์์ต๋๋ค.
- ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ Step ๋ฉ์๋(scopeStep1)๋ฅผ ํธ์ถํ ๋ ์ค์ Bean ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ณ ์ด ์์ ์ Step Bean์ด ์์ฑ๋ฉ๋๋ค.
- 5.์์ ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ ์ฐธ์กฐํ Bean์ JobScope์์ ์ฐพ์ต๋๋ค. (JobScope๋ JobContext๋ฅผ ํตํด ์ฐพ์ต๋๋ค.)
- JobContext์์ ์ค์ Bean์ด ์กด์ฌํ๋ฉด Bean์ ๊บผ๋ด ์ฐธ์กฐํ์ฌ ์ค์ Step์ ์คํํฉ๋๋ค.
- JobContext์์ ์ค์ Bean์ด ์กด์ฌํ์ง ์์ผ๋ฉด ์คํ๋ง์ BeanFactory๋ฅผ ํตํด ์ค์ Step์ ์์ฑํ๊ณ , ์ด ์์ ์์ ์ค์ scopeStep1() ๋ฉ์๋๋ฅผ ํธ์ถํด์ Bean์ ์์ฑํฉ๋๋ค. ๋ํ @Value ๋ฐ์ธ๋ฉ ์ฒ๋ฆฌ๋ ๊ฐ์ด ์งํ์ด ๋ฉ๋๋ค.
- ๊ทธ ํ ์์ฑ๋ Step Bean์ JobContext์ ์ ์ฅํ๊ณ , ์ดํ์๋ JobContext์์ Bean์ ๋ฐ๋ก ๊บผ๋ด์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
5. ๋ด๋ถ ์ฝ๋
JobScope, StepScope ๋ชจ๋ ๋ด๋ถ ๋ก์ง์ ๋น์ทํ๊ธฐ์ JobScope์ ์ฝ๋๋ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
AbstractBatchConfiguration ์ถ์ ํด๋์ค ๋ด๋ถ์ ์กด์ฌํ๋ ScopeConfiguration ํด๋์ค์์ StepScope, JobScope๋ฅผ ์์ฑํฉ๋๋ค.
์ ์ฝ๋์์ @Configuration(proxyBeanMethods = false)๋ก ์ค์ ์ด ๋์ด์๋๋ฐ์, ์ด๋ ํ๋ก์๋ฅผ ์ ์ฉํ์ง ์๊ณ ์ค๋ณต ์ฝ๋์ ์ํด ๋์ผํ ์ธ์คํด์ค๊ฐ ์์ฑ๋๋๋ผ๋ ์ฑ๊ธํค์ผ๋ก ์์ฑํ์ง ์์ต๋๋ค.
๊ด๋ จํด์๋ ์๋ ๋งํฌ๋ค์ ์ฐธ๊ณ ํด ์ฃผ์ธ์.
- https://stackoverflow.com/questions/61266792/when-to-set-proxybeanmethods-to-false-in-springs-configuration
- https://sujl95.tistory.com/69
- https://mangkyu.tistory.com/234
JobScope ํด๋์ค์ get() ๋ฉ์๋์์ JobContext๋ฅผ ํตํด Bean์ด ์กด์ฌํ๋์ง ํ์ธํฉ๋๋ค.
Bean์ด ์กด์ฌํ์ง ์์ ๊ฒฝ์ฐ ์์ฑ & ์ ์ฅ์ ํ๊ณ , ์กด์ฌํ ๊ฒฝ์ฐ Bean์ ๊ฐ์ ธ์ ๋ฐ๋ก ๋ฆฌํดํฉ๋๋ค.
26๋ผ์ธ์์ Job์ start() ๋ฉ์๋์์ Step ํธ์ถ ์ ์ค์ Step์ด ์๋ Proxy๊ฐ ์์ฑ๋ฉ๋๋ค.
์ 115๋ผ์ธ์ step.getName() ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์๊ฐ Proxy ๊ฐ์ฒด๊ฐ ์ฐธ์กฐํ ์ค์ Bean์ ์์ฑํฉ๋๋ค.
(์ step์ ์ค์ ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ ์ด๋ฏ๋ก Proxy ๊ฐ์ฒด์ ๋๋ค.)
step.getName() ๋ฉ์๋๋ฅผ ํธ์ถํด ๋ณด๋ฉด AbstractStep ์ถ์ ํด๋์ค์ getName() ๋ฉ์๋๋ฅผ ํธ์ถํด์ผ ํ์ง๋ง Proxy ๊ฐ์ฒด์ด๋ฏ๋ก JdkDynamicAopProxy ํด๋์ค์ invoke() ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
Proxy์ targetSoucre๊ฐ ์ค์ Bean์ธ scopeStep1์ ํ์ธํ ์ ์์ต๋๋ค.
Proxy์์ ์ค์ ์ฐธ์กฐํ Bean์ ๊ตฌํ ๋(์ ์ฌ์ง, 195๋ผ์ธ) ํ์ํ๊ฒ JobScope์ ๋๋ค.
JobScope์ get() ๋ฉ์๋์์ ์ต์ด Job ํธ์ถ ์ JobContext ๋ด์ ์ค์ Bean์ด ์กด์ฌํ์ง ์์ผ๋ฏ๋ก 185~186 ๋ผ์ธ์ ํตํด Bean์ ์์ฑํ๊ณ (185 ๋ผ์ธ), JobContext์ ์ค์ Bean์ ์ ์ฅ(186 ๋ผ์ธ)ํฉ๋๋ค.
๋ํ ์ด๋ ์ค์ Step์ธ scopeStep1() ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
ํ์ง๋ง ํ์ฌ ์ ์ ์ํฉ์ Job์ ์ฒ์ ์คํํ ๊ฒ ์๋ ๋ ๋ฒ์งธ ์คํํ ์ํฉ์ด๋ฏ๋ก ์ธ์์ธ name์ ํด๋นํ๋ ์ค์ Bean์ JobContext์์ ๋ฐ๋ก ๊ฐ์ ธ์จ ํ ๋ฆฌํดํ๊ณ , ์ดํ AbstractStep ์ถ์ ํด๋์ค์ getName() ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๊ฐ์ ์ป์ต๋๋ค.
์ด์์ผ๋ก @JobScope, @StepScope์ ๋ํด ์ดํด๋ณด์์ต๋๋ค.
์ ๋ฆฌํ๋ฉด์๋ ์ด๋ ค์ด ๋ด์ฉ๋ ๋ง์๊ณ , ์๋ชป ์์ฑํ ๋ด์ฉ์ด ์์์๋ ์์ต๋๋ค...๐
๋ค์๋ถํด Spring Batch์์ ์ฒญํฌ ํ๋ก์ธ์ค ๋ฐฉ์์ ๋ํด ์ ๋ฆฌํด๋ณด๊ฒ ์ต๋๋ค.
์ฐธ๊ณ ๋ฌธ์
- https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#late-binding
- https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B0%B0%EC%B9%98/dashboard
'Spring > Spring Batch' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring Batch (12) Retry (2) | 2023.03.04 |
---|---|
Spring Batch (11) Repeat (0) | 2023.01.15 |
Spring Batch (9) JobParametersValidator (0) | 2022.11.13 |
Spring Batch (8) JobLauncher (0) | 2022.11.11 |
Spring Batch (7) JobRepository (0) | 2022.11.08 |
๋๊ธ