#11 ๋น ์ค์ฝํ(+Provider, ํ๋ก์ ๋ชจ๋)
by JiwonDev์์์ ์ฐ๋ฆฌ๋ ์คํ๋ง ๋น์ ์คํ๋ง ์ปจํ ์ด๋์ ์์๊ณผ ํจ๊ป ์์ฑ๋๊ณ , ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋ ๋ ๊น์ง ์ ์ง๋๋ค๊ณ ํ์ตํ๋ค. ์ด๋ ์คํ๋ง ๋น์ด ๊ธฐ๋ณธ์ ์ผ๋ก '์ฑ๊ธํค ์ค์ฝํ'๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ด๋ค. ์ฌ๊ธฐ์์ ์ค์ฝํ๋ ๋ง ๊ทธ๋๋ก ๋น์ด ์กด์ฌํ ์ ์๋ ์๋ช ์ฃผ๊ธฐ ๋ฒ์๋ฅผ ์๋ฏธํ๋ค.
# ์คํ๋ง์ด ์ง์ํ๋ ๋ค์ํ ์ค์ฝํ
ํ์ง๋ง ํ์์ ๋ฐ๋ผ ์คํ๋ง ๋น์ ์๋ช ์ฃผ๊ธฐ, ์ฆ ์ค์ฝํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค. ์คํ๋ง์ ๋ค์ํ ์ค์ฝํ๋ฅผ ์ง์ํ๋ค.
- ์ฑ๊ธํค(๊ธฐ๋ณธ) : ์คํ๋ง ์ปจํ ์ด๋์ ์์๊ณผ ์ข ๋ฃ๊น์ง ์ ์ง๋๋ ๊ฐ์ฅ ๋์ ๋ฒ์์ ์ค์ฝํ์ด๋ค.
- ํ๋กํ ํ์ : ์คํ๋ง ์ปจํ ์ด๋๋ ํ๋กํ ํ์ ๋น์ ์์ฑ๊ณผ ์์กด๊ด๊ณ ์ฃผ์ ๊น์ง๋ง ๊ด์ฌํ๊ณ , ์ดํ ๋ฐ๋ก ๊ด๋ฆฌํ์ง ์๋๋ค. ์ฆ ์คํ๋ง์์ ๋งค์ฐ ์งง์ ๋ฒ์์ ์ค์ฝํ์ด๋ค. (= ์ข ๋ฃ ์ฝ๋ฐฑ๋ฉ์๋ ํธ์ถ์ด ๋์ง ์๋๋ค.)
- ์น ๊ด๋ จ ์ค์ฝํ๋ค
- request : ์น ์์ฒญ์ด ๋ค์ด์ค๊ณ ๋๊ฐ๋ ๊น์ง ์ ์ง๋๋ ์ค์ฝํ์ด๋ค.
- session: ์น ์ธ์ ์ด ์์ฑ๋๊ณ ์ข ๋ฃ๋ ๋ ๊น์ง ์ ์ง๋๋ ์ค์ฝํ์ด๋ค.
- application: ์น์ ์๋ธ๋ฆฟ ์ปจํ ์คํธ์ ๊ฐ์ ๋ฒ์๋ก ์ ์ง๋๋ ์ค์ฝํ์ด๋ค
๋ฌผ๋ก ์์ง ์์ฑ๋์ง ์์ ์คํ๋ง๋น (ex request๋น์ ์ฑ๊ธํค์ ์ฃผ์
ํ๋ ค๊ณ ํ๋๊ฒฝ์ฐ)์ ์ฌ์ฉํ๋ฉด ์คํ๋ง์ฑ์ด ์๋ฌ๋ค. ์ค๋ฅ๋ฐ์.
๋ง์ฝ ํ์ํ๋ค๋ฉด DL(Dependcy Lookup) ๊ธฐ๋ฅ์ธ ObjectProvider ๋ฑ์ ์ฌ์ฉํ๋ฉด๋๋ค. ์ด๋ ์๋์์ ์ค๋ช
.
# ์คํ๋ง ๋น ์ค์ฝํ ์ค์ ๋ฐฉ๋ฒ
@Scope("prototype")
@Component // ์ปดํฌ๋ํธ ์ค์บ์ ์ด์ฉํ ์๋ ๋ฑ๋ก
public class HelloBean {}
@Scope("prototype")
@Bean // ์คํ๋ง ๋น ์๋ ๋ฑ๋ก.
PrototypeBean HelloBean() {
return new HelloBean();
}
# ํ๋กํ ํ์ ์ค์ฝํ๋
๊ธฐ์กด์ ์ฑ๊ธํค ์ค์ฝํ ๋น์ ์กฐํํ๋ฉด, ์คํ๋ง ์ปจํ ์ด๋๋ ํญ์ ๊ฐ์ ์ธ์คํด์ค์ ์คํ๋ง ๋น์ ๋ฐํํ๋ค. ์ด๋ ์ฑ๊ธํค ์ค์ฝํ์ ๋น์ด ์ปจํ ์ด๋์ ์์ฑ๋ถํฐ ์ข ๋ฃ๊น์ง ํจ๊ปํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ฑ๊ธํค ๋น์ ์์กด์ฑ ์ฃผ์ (DI)์ ํ๋ ์ง ApplicationContext๋ฅผ ์ด์ฉํด์ ๋น์ ๋ถ๋ฌ์ค๋์ง ๋งค๋ฒ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค. ๊ทธ๋ฐ๋ฐ ๋๋ก๋ ๋น์ ์ฑ๊ธํค์ด ์๋ ํ๋์ ๋น์ผ๋ก ์ฌ๋ฌ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํด์ผ ํ ๋๊ฐ ์๋ค.
๊ทธ๋ด ๋ ํ๋กํ ํ์ ๋น์ ์ฌ์ฉํ๋๋ฐ ํ๋กํ ํ์ ๋น์ ์ปจํ ์ด๋์๊ฒ ๋น์ ์์ฒญํ ๋๋ง๋ค ๋งค๋ฒ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํด์ค๋ค.
ํ๋กํ ํ์ ๋น์ ๊ฒฝ์ฐ ์์ฑ, ์์กด์ฑ์ฃผ์ +์ด๊ธฐํ ์ดํ ์คํ๋ง ์ปจํ ์ด๋์์ ๊ด๋ฆฌํ์ง ์๋๋ค. ์ฆ ํธ์ถํ ๋ ๋ง๋ค ์๋ก์ด ๋น ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉฐ ์ข ๋ฃํ ๋๋ ๋ฐ๋ก ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํด์ฃผ๋ ์ฝ๋ฐฑ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ๋ง์ฝ @PreDestory ๊ฐ์ ์ข ๋ฃ ๋ฉ์๋ ํธ์ถ์ด ํ์ํ๋ค๋ฉด, ํด๋น ๋น์ ์กฐํํ ํด๋ผ์ด์ธํธ์์ ๋ฐ๋ก ๊ด๋ฆฌํด์ฃผ์ด์ผ ํ๋ค.
@ ์ฑ๊ธํค๊ณผ ํ๋กํ ํ์ ์ ํจ๊ป ์ฌ์ฉํ ๋ ๋ฌธ์ ์
์คํ๋ง ์ปจํ ์ด๋์ ํ๋กํ ํ์ ์ค์ฝํ ๋น์ ์์ฒญํ๋ฉด ํญ์ ์๋ก์ด ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ๋ฐํํ๋ค.
@Scope("prototype")
@Component
public class HelloBean {}
๊ฐ๊ฐ ๋ค๋ฅธ ์ธ์คํด์ค ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ addCount()๋ก ์นด์ดํธ๋ฅผ ์ฆ๊ฐ์์ผ๋ ๊ฐ๊ฐ ๊ณ ์ ํ count๋ฅผ ๊ฐ์ง๋ค.
๋ง์ฝ ์ฑ๊ธํค ๋น(clientBean)์ด ์์กด๊ด๊ณ ์ฃผ์ ์ ํตํด์ ํ๋กํ ํ์ ๋น(PrototypeBean)์ ์ฃผ์ ๋ฐ์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
- clientBean์ ์ฑ๊ธํค์ด๋ฏ๋ก, ์คํ๋ง ์ปจํ ์ด๋ ์์ฑ ์์ ์ ํจ๊ป ์์ฑ๋๊ณ ์์กด๊ด๊ณ ์ฃผ์ ๋ ๋ฐ์ํ๋ค.
- clientBean์ ์์กด๊ด๊ณ ์๋ ์ฃผ์ ์ ์ฌ์ฉํ๋ค. ์ฆ ์ฃผ์ ์์ ์ ์คํ๋ง ์ปจํ ์ด๋์์ ํ๋กํ ํ์ ๋น์ ์์ฒญํ๊ฒ ๋๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ ํ๋กํ ํ์ ๋น์ ์์ฑํ์ฌ clientBean์ ๋ฐํํ๋ค.
- clientBean์ ํ๋กํ ํ์ ๋น์ ๋ด๋ถ ํ๋์ ๋ณด๊ดํ๋ค. (์ ํํ๋ ์ธ์คํด์ค๊ฐ ์๋ ์ฐธ์กฐ๊ฐ์ ๋ณด๊ดํ๋ค.)
์ด ์ํฉ์์ addCount()๋ฅผ ํด๋ผ์ด์ธํธ๋ง๋ค ํธ์ถํ๊ฒ ๋๋ฉด ์ด๋ป๊ฒ ๋ ๊น? ๊ธฐ์กด์ ํ๋กํ ํ์ ๋น์ฒ๋ผ ๊ฐ๊ฐ ๊ณ ์ ํ count๊ฐ์ ๊ฐ์ง๊น?
์๋๋ค. ํด๋ผ์ด์ธํธ๋ clientBean์ ์คํ๋ง ์ปจํ ์ด๋์ ์์ฒญํด์ ๋ฐ๋๋ค. ์ฑ๊ธํค ๊ฐ์ฒด์ด๋ฏ๋ก ํญ์ ๊ฐ์ clientBean์ด ๋ฐํ๋๋ค. ์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์, clientBean์ด ๋ด๋ถ์ ๊ฐ์ง๊ณ ์๋ ํ๋กํ ํ์ ๋น์, ์ด๋ฏธ ๊ณผ๊ฑฐ์ ์ฃผ์ ์ด ๋๋ ๋น์ด๋ค. ์ฆ ์ฌ์ฉํ ๋ ๋ง๋ค ์๋ก ์์ฑ๋์ง ์๋๋ค. (* ํ๋กํ ํ์ ๋น์ ์ฃผ์ ์์ ์์๋ง ์๋กญ๊ฒ ์์ฑ๋๋ค.)
์คํ๋ง์ ์ผ๋ฐ์ ์ผ๋ก ์ฑ๊ธํค ๋น์ ์ฌ์ฉํ๋ฏ๋ก, ๋ณดํต ์ฑ๊ธํค ๋น์ด ํ๋กํ ํ์ ๋น์ ์ฃผ์ ๋ฐ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ํ์ง๋ง ์ฑ๊ธํค๋น์ ์์ฑ ์์ ์๋ง ์์กด๊ด๊ณ ์ฃผ์ ์ ๋ฐ๊ธฐ ๋๋ฌธ์ ์ฃผ์ ๋ฐ์ ํ๋กํ ํ์ ๋น์ด ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ์ ์ง๋๋ ๋ฌธ์ ๊ฐ ์๋ค.
ํ๋กํ ํ์ ๋น์ ์ฃผ์ ์์ ์๋ง ์๋ก ์์ฑํ๊ณ ์ถ์๊ฒ ์๋๋ผ, ์ฌ์ฉํ ๋ ๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํด ๋ฐํํ๋ ๊ฒ์ ์๋ํ๊ณ ๋ง๋ค์์ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ด๋ป๊ฒ ํ๋ฉด ์ํ๋๋๋ก ๋์ํ๊ฒ ๋ฐ๊ฟ ์ ์์๊น?
@ ํด๊ฒฐ์ฑ
์ฌ์ค ๊ฐ์ฅ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ ์ฑ๊ธํค ๊ฐ์ฒด์์ ํ๋กํ ํ์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ๋ ๋ง๋ค ์๋กญ๊ฒ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ฉด ๋๋ค. ์ฐธ๊ณ ๋ก ์ด๋ ๊ฒ ์์กด๊ด๊ณ๋ฅผ ์ธ๋ถ์์ ์ฃผ์ (DI)๋ฐ๋๊ฒ ์๋๋ผ ๊ฐ์ฒด ๋ด๋ถ์์ ์ปจํ ์ด๋(App..Context)์ ์๋ ์์กด๊ด๊ณ๋ฅผ ์ฐพ๋ ๊ฒ์ Dependency Lookup(DL, ์์กด๊ด๊ณ ํ์)๋ผ๊ณ ๋ถ๋ฅธ๋ค.
class ClientBean {
@Autowired
private ApplicationContext ac;
public int logic() {
// ๋ก์ง์ ์คํํ ๋ ๋ง๋ค ์๋ก์ด ๊ฐ์ฒด ์์ฑ
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
}
- ์คํํด๋ณด๋ฉด logic()์ ์คํ ํ ๋ ๋ง๋ค ac.getBean()์ ํตํด ์๋ก์ด ํ๋กํ ํ์ ๋น์ด ์์ฑ๋๋ค.
- ๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ์คํ๋ง ์ฑ ์ปจํ ์คํธ๋ฅผ ์ฃผ์ ๋ฐ๊ฒ ๋๋ฉด, ์คํ๋ง ์ปจํ ์ด๋(App..Context)์ ์ข ์์ ์ธ ์ฝ๋๊ฐ ๋ง๋ค์ด์ ธ ์ ์ง๋ณด์๊ฐ ์ด๋ ต๊ณ ๋จ์ํ ์คํธ๋ ๋งค์ฐ ๊น๋ค๋ก์์ง๋ค.
- ๊ทธ๋ ๋ค๋ฉด ์คํ๋ง์์ Denpendency Lookup์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ ์์๊น?
@ ObjectFactory, ObjectProvider
์ง์ ํ ๋น์ ์ปจํ ์ด๋์์ ๋์ ์ฐพ์์ฃผ๋ DL์๋น์ค๋ฅผ ์ ๊ณตํด์ฃผ๋ ๊ฒ์ด ๋ฐ๋ก ObjectProvider ์ด๋ค. ๊ณผ๊ฑฐ์๋ ObjectFactory๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ฌ๊ธฐ์ ์ฌ๋ฌ ํธ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ฌ ๋ง๋ ๊ฒ์ด ObjectProvider์ด๋ค. ์ด๋ ์คํ๋ง์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ด๋ผ ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ์ง ์๊ณ , ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ค. (๋์ ์คํ๋ง์ ์์กด์ ์ด๋ค. ๋ค๋ฅธ๊ณณ์์ ์ฌ์ฉX)
- ObjectProvider : ObjectFactory๋ฅผ ์์, ์ต์ ์ด๋ ์คํธ๋ฆผ ์ฒ๋ฆฌ๋ฑ ํธ์๊ธฐ๋ฅ ์ ๊ณต. ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์์์.
static class ClientBean {
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
}
- prototypeBeanProvider.getObject()๋ฅผ ํตํด์ ์๋ก์ด ํ๋กํ ํ์ ๋น์ด ์์ฑ๋๋ค.
- ObjectProvider์ getObject()๊ฐ ํธ์ถ๋๋ฉด, ๋ด๋ถ์์ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํตํด ํด๋น ๋น์ ์ฐพ์์ ๋ฐํํ๋ค. (DL)
- ์คํ๋ง์ด ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง๋ง, ๊ธฐ๋ฅ์ด ๋จ์ํด์ ๋จ์ํ ์คํธ๋ฅผ ๋ง๋ค๊ฑฐ๋ mock ์ฝ๋(๊ฐ์ง ๊ฐ์ฒด๋ฅผ ์ด์ฉํ ํ ์คํธ)๋ฅผ ๋ง๋ค๊ธฐ ์ฝ๋ค.
* ApplicationContext๋ฅผ mock์ผ๋ก ๋ง๋ค๋ ค๋ฉด ๊ทธ๊ณณ์ ์๋ ์ ๋ง์ ์ธํฐํ์ด์ค๋ฅผ ๋ชจ๋ ๊ตฌํํด์ผ ํ๋ค. ๋ฐ๋ฉด์ ObjectProvider๋ฅผ ์ฌ์ฉํ๋ฉด ๊ทธ ๊ณณ์์ ์ ๊ณตํ๋ ๋งค์ฐ ์ ์ ์ธํฐํ์ด์ค๋ง ๊ตฌํํด๋ ๋๋ฏ๋ก ํ ์คํธ๋ mock์ ์๋์ ์ผ๋ก ์ฝ๊ฒ ๋ง๋ค ์ ์๋ค.
@ JSR-330 Provider (JSR-330 ์๋ฐ ํ์ค)
๋ค๋ง ์์ ObjectProvider๋ ์คํ๋ง ํ๋ ์์ํฌ์์๋ง ์ฌ์ฉํ ์ ์๋, ์คํ๋ง์ ์์กด์ ์ธ ๋ฐฉ๋ฒ์ด์๋ค. ์์กด์ ์ด์ง ์๊ฒ ์๋ฐ ํ์ค(javax.inject.Provider)์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
์ฐธ๊ณ ๋ก ์คํ๋ง ํ๋ ์์ํฌ์์ ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด build.gradle์ ์๋์ ๊ฐ์ ์ค์ ์ ์ถ๊ฐํด์ฃผ๋ฉด ๋๋ค.
implementation 'javax.inject:javax.inject:1'
- ์๋ ์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด provider.get()์ ํตํด ํญ์ ์๋ก์ด ํํ ํ ํ์ ๋น์ด ์์ฑ๋๋ค.
- ObjectProvider์ ๋น์ทํ๊ฒ provider์ get()์ ํธ์ถํ๋ฉด ์คํ๋ง ์ปจํ ์ด๋์์ ํด๋น ๋น์ ์ฐพ์ ๋ฐํํ๋ค(DL)
- ์ด๋ ์คํ๋ง์ ๊ธฐ๋ฅ์ด ์๋ ์๋ฐ ํ์ค์ด๊ธฐ์ ๋จ์ํ ์คํธ๋ ์ฝ๋์ ์ ์ฐ์ฑ์ด ํจ์ฌ ์ข๋ค.
- get() ๋ฉ์๋ ํ๋๋ก ๊ธฐ๋ฅ์ด ๋งค์ฐ ๋จ์ํ๋ฉฐ, ์๋ฐ ํ์ค์ด๋ฏ๋ก ์คํ๋ง์ด ์๋ ๋ค๋ฅธ ์ปจํ ์ด๋์์๋ ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
- ๋ค๋ง ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ (javax.inject)๊ฐ ํ์ํ๋ค.
package javax.inject;
public interface Provider<T> {
T get();
}
//implementation 'javax.inject:javax.inject:1' gradle ์ถ๊ฐ ํ์
static class ClientBean {
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
@ ์ ๋ฆฌ
์ฌ์ค ์ค๋ฌด์์ ์น ์ฑ์ ๊ฐ๋ฐํ๋ค๋ณด๋ฉด, ๋๋ถ๋ถ ์ฑ๊ธํค ๋น์ผ๋ก ํด๊ฒฐํ ์ ์๊ธฐ์ ํ๋กํ ํ์ ๋น์ ์ฌ์ฉํ๋ ์ผ์ ๋๋ฌผ๋ค. ํ์ง๋ง ์์์ ๋ฐฐ์ด ObjectProvider, javax.inject.Provider๋ ํ๋กํ ํ์ ๋น ๋ฟ๋ง ์๋๋ผ ์์ ๊ฐ์ด ์ปจํ ์ด๋์์ ํ์ํ ์์กด์ฑ์ ์ฐพ์ ์ง์ ์ฃผ์ ํ๋ DL(Dependency Lookup)์ด ํ์ํ ๊ฒฝ์ฐ ์ธ์ ๋ ์ง ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ด๋ค.
๋ํ Provider๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์์ ๊น์ง ๋น ์์ฑ์ ์ง์ฐ์ํฌ ์ ์์ด์, ์๋์ ์น ์ค์ฝํ์์ ์ฌ์ฉํ๊ธฐ ์ข๋ค. (๋น ์ค์ฝํ๊ฐ ์ปจํ ์ด๋์ ํจ๊ป ๋น์ ์์ฑํ์ง ์๊ณ ๊ณ ๊ฐ์ ์์ฒญ์ด ๋ค์ด์์ผ ์์ํ๊ธฐ ๋๋ฌธ.)
* ObjectProvider๋ DL์ ์ํ ํธ์ ๊ธฐ๋ฅ์ ๋ง์ด ์ ๊ณตํด์ฃผ๊ณ , ์คํ๋ง์ ์ฌ์ฉํ๋ฉด ๋ณ๋์ ์ค์ ์์ด ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ด ํจ์ฌ ํธ๋ฆฌํ๋ค. ๋ง์ฝ ๋ค๋ฅธ ์ปจํ ์ด๋์๋ ์ฌ์ฉ ํ ์ ์๊ฒ ์ค๊ณํด์ผํ๋ค๋ฉด ์๋ฐ ํ์ค Provider๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. ๊ทผ๋ฐ ๋ณดํต ๊ทธ๋ฐ ์ผ์ ์ ์๊ธดํ๋ค.
* ์ฐธ๊ณ ๋ก ์คํ๋ง์ด ์ ๊ณตํ๋ ๋ฉ์๋์ @Lookup ์ด๋
ธํ
์ด์
์ด ์๊ธด ํ์ง๋ง, ์ด์ ๋ฐฉ๋ฒ๋ค๋ก ์ถฉ๋ถํ๊ธฐ๋ ํ๊ณ ํด๋น ์ด๋
ธํ
์ด์
์ ์ฌ์ฉ์ ์กฐ์ฌํด์ผ ๋ ๋ถ๋ถ์ด ๋ง์์ ๊ตณ์ด ์ค๋ช
ํ์ง๋ ์๊ฒ ๋ค. ์ฐ์ง๋ง์.
@Component
@Scope("prototype")
public class SchoolNotification {
// ... prototype-scoped state
}
// @Lookup์ ๋ฌ๋ฉด, ๋งค๋ฒ ์๋กญ๊ฒ ์์ฑํด์ค๋ค.
@Component
public class StudentServices {
// ... member variables, etc.
@Lookup
public SchoolNotification getNotification() {
return null;
}
// ... getters and setters
}
์ฐธ๊ณ ๋ก ์ด๋ ๊ฒ @Lookup๋ฑ์ ์ฌ์ฉํ๋ฉด, ์ฑ๊ธํค ๊ฐ์ฒด์๋ ํ๋ก์๊ฐ ์ฝ์
๋์ด ์๋ค.
๊ทธ๋ฆฌ๊ณ ์๋์ ๊ฐ์ด ์ฌ์ฉํ ๋ ๋ง๋ค ํด๋น ํ๋ก์์์ new Prototype ์ธ์คํด์ค๋ฅผ ์์ฑํด์ฃผ๋ ํ์.
# ์น ์ค์ฝํ
์น ์ค์ฝํ๋ ์น ํ๊ฒฝ์์๋ง ๋์ํ๋ค. ์น ์ค์ฝํ๋ ํ๋กํ ํ์ ๊ณผ๋ ๋ค๋ฅด๊ฒ ์คํ๋ง์ด ํด๋น ์ค์ฝํ์ ์ข ๋ฃ์์ ๊น์ง ๊ด๋ฆฌํ๋ค. (=์ข ๋ฃ ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.) ๊ธฐ์กด์ ์ฌ์ฉํ๋ ์ฑ๊ธํค ๋น์ ์คํ๋ง ์ฑ์ด ์คํํ๋ ์์ ์ ์์ฑํด์ ์ฃผ์ ์ด ๊ฐ๋ฅํ์ง๋ง, ์น ์ค์ฝํ ๋น์ ์ค์ ์์ฒญ์ด ๋ค์ด์์ผ ์์ฑํ ์ ์๋ค.
์ฐธ๊ณ ๋ก ์คํ๋ง ๋ถํธ์์๋ ์๋์ ๊ฐ์ด ์น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์๋ค. ์น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ถ๊ฐ๋๋ฉด ๊ธฐ์กด์ ์ฌ์ฉํ๋ ์ปจํ ์ด๋ ๊ตฌํ์ฒด(AnnotationConfigApp..Context) ๋์ ์ AnnotationConfigServletWebServerApplicationContext๋ฅผ ์ฌ์ฉํ๋๋ก ๋ฐ๋๋ค. ์ด๋ ์น๊ณผ ๊ด๋ จ๋ ์ถ๊ฐ ์ค์ ๋ค๊ณผ ํ๊ฒฝ์ ์ ๊ณตํด์ค๋ค.
//web ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ
implementation 'org.springframework.boot:spring-boot-starter-web'
@Component
@Scope(value = "request") // ์น request ์ค์ฝํ
public class MyLogger {
public void setRequestURL(String requestURL) {
this.requestURL = requestURL; // ๊ฐ์ฒด ์์ฑ ์ดํ ์ธ๋ถ์์ setter๋ก ์ฃผ์
๋ฐ๋๋ค.
}
... ์๋ต ...
@PostConstruct // request ์์ฒญ์ด ๋ค์ด์ฌ ๋, ๋น ์์ฑ
public void init() {
uuid = UUID.randomUUID().toString(); // UUID๋ฅผ ์ด์ฉํด ๊ฐ ์์ฒญ์ ๊ตฌ๋ถ
System.out.println("[" + uuid + "] request scope bean create:" + this);
}
@PreDestroy // ์์
์ข
๋ฃ. ๋น ์๋ฉธ
public void close() {
System.out.println("[" + uuid + "] request scope bean close:" + this);
}
}
์ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด HTTP Request ์์ฒญ์ด ์ฌ ๋ ๋ง๋ค ์๋์ ๊ฐ์ ์ฝ์ ๋ก๊ทธ๋ฅผ ์ป์ ์ ์๋ค.
[d06b992f...] request scope bean create
// ์์
์์
[d06b992f...][http:\\localhost:8080\log-demo] controller test
[d06b992f...][http:\\localhost:8080\log-demo] service id = testId
// ์์
๋
[d06b992f...] request scope bean close
@ ์น ์ค์ฝํ ์ข ๋ฅ
์ธ์ , ์๋ธ๋ฆฟ ์ปจํ ์คํธ, ์น ์์ผ ๊ฐ์ ์ฉ์ด๋ฅผ ์๋ค๋ฉด ์ฝ๊ฒ ์ดํดํ ์ ์๋ค. ์๋์ ์ค์ฝํ๋ค๋ ๊ฒฐ๊ตญ ์ ์ฉ๋ฒ์๋ง ๋ค๋ฅผ ๋ฟ, ์ ์์ ์ requset์ ํฌ๊ฒ ๋ค๋ฅด์ง์๋ค.
@Component
@Scope(value = "request") // ์น request ์ค์ฝํ
public class MyLogger {...}
- request : HTTP ์์ฒญ ํ๋๊ฐ ๋ค์ด์ค๊ณ ๋๊ฐ ๋ ๊น์ง ์ ์ง๋๋ ์ค์ฝํ, ๊ฐ๊ฐ์ 'HTTP ์์ฒญ๋ง๋ค' ๋ณ๋์ ๋น
์ธ์คํด์ค๊ฐ ์์ฑ๋๊ณ , ๊ด๋ฆฌ๋๋ค. ์ฆ ๊ฐ์ ์์ฒญ์ด๋ฉด ๊ฐ์ ์ธ์คํด์ค๊ฐ ๋ด๋นํ๊ฒ ๋ง๋ค์ด์ค๋ค. - session : HTTP Session๊ณผ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
- application : ์๋ธ๋ฆฟ ์ปจํ ์คํธ( ServletContext )์ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
- websocket : ์น ์์ผ๊ณผ ๋์ผํ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ง๋ ์ค์ฝํ
์ฌ์ค ์ค์ฝํ๋ฅผ ์ง์ ํ์ง ์๊ณ ์ฌ์ฉํ๋ค๊ณ ํด์, ๊ฐ์๊ธฐ ๋ฌธ์ ๊ฐ ์๊ธฐ์ง๋ ์๋๋ค. ํ์ง๋ง request scope๋ฑ์ ์ฌ์ฉํ์ง ์๊ณ ํ๋ผ๋ฉํ๋ก ๋ชจ๋ ์ ๋ณด๋ฅผ ์๋น์ค ๊ณ์ธต(๋น์ฆ๋์ค ๋ก์ง์ด ์๋ ๊ณณ)์ ๋๊ธด๋ค๋ฉด ๊ด๋ฆฌํ๋ ํ๋ผ๋ฉํ๊ฐ ๋ง์ ์ง์ ๋ถํด์ง๋ค.
๋ ๋ฌธ์ ๋ requestURL ๊ฐ์ ์น๊ณผ ๊ด๋ จ๋ ์ ๋ณด๊ฐ, ์ ํ ๊ด๋ จ์๋ ๋น์ฆ๋์ค ์๋น์ค ๊ณ์ธต๊น์ง ๋์ด๊ฐ๋ค๋ ๊ฒ์ด๋ค. ์น๊ณผ ๊ด๋ จ๋ ๋ถ๋ถ์ ์ปจํธ๋กค๋ฌ๊น์ง๋ง ์ฌ์ฉํด์ผ ํ๋ค. ์๋น์ค ๊ณ์ธต์ ์น ๊ธฐ์ ์ ์ข ์๋์ง์๊ณ ๊ณ์ธต์ ๋ถ๋ฆฌํด์ ๋ง๋๋ ๊ฒ์ด ์ ์ง๋ณด์๋ ํ์ฅ์ ์ข๊ธฐ ๋๋ฌธ์ด๋ค.
# ์ค์ฝํ์ ํ๋ก์
๋ํ Provider๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ์์ ๊น์ง ๋น ์์ฑ์ ์ง์ฐ์ํฌ ์ ์์ด์, ์๋์ ์น ์ค์ฝํ์์ ์ฌ์ฉํ๊ธฐ ์ข๋ค. (๋น ์ค์ฝํ๊ฐ ์ปจํ ์ด๋์ ํจ๊ป ๋น์ ์์ฑํ์ง ์๊ณ ๊ณ ๊ฐ์ ์์ฒญ์ด ๋ค์ด์์ผ ์์ํ๊ธฐ ๋๋ฌธ.)
์ฌ์ค ์ด๋ Provider ๋์ ํ๋ก์๋ฅผ ์ด์ฉํด์ ๋ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์๋ค.
ํ๋ก์ ์์ฒด๋ฅผ ์ ๋ชจ๋ฅธ๋ค๋ฉด, ๋์ค์ ๋ค์ ์์๋ณด๋๋กํ๊ณ ์ด๋ฐ ๋ฐฉ๋ฒ์ด ์๋ค๋ ๊ฒ๋ง ๊ธฐ์ตํ๊ณ ์์. ํ๋ก์๋ ์๋์ ๊ฐ์ด proxyMode๋ฅผ ์ด์ฉํด์ ์ค์ ํ ์ ์๋ค.
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}
- ์ ์ฉ ๋์์ด ์ธํฐํ์ด์ค๋ฉด .INTERFACES ๋ฅผ ์ ํํ๋ฉด ๋๋ค.
- ์ด๋ ๊ฒ ํ๋ฉด MyLogger์ ๊ฐ์ง ํ๋ก์ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋๊ณ HTTP request์ ์๊ด ์์ด ๊ฐ์ง ํ๋ก์ ํด๋์ค๋ฅผ ๋ค๋ฅธ ๋น์ ๋ฏธ๋ฆฌ ์ฃผ์ ํด ๋ ์ ์๋ค. ์ฐ๋ฆฌ๋ Provider๋ฅผ ์ ๊ฒฝ์ฐ์ง ์๊ณ , ํด๋์ค ์ฌ์ฉํ๋ฏ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
- ์์กด๊ด๊ณ ์ฃผ์ ๋ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๊ฐ ์ฃผ์ ๋๊ฒ ๋๋ค.
@ Provider๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
@Controller
@RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final ObjectProvider<MyLogger> myLoggerProvider;
@RequestMapping("log-demo")
@ResponseBody
public String logDemo(HttpServletRequest request) {
String requestURL = request.getRequestURL().toString();
MyLogger myLogger = myLoggerProvider.getObject();
myLogger.setRequestURL(requestURL);
myLogger.log("controller test");
logDemoService.logic("testId");
return "OK";
}
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final ObjectProvider<MyLogger> myLoggerProvider;
public void logic(String id) {
MyLogger myLogger = myLoggerProvider.getObject();
myLogger.log("service id = " + id);
}
}
@ ํ๋ก์(MyLogger์ ๊ฐ์ง ํ๋ก์ ํด๋์ค)๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ
@Controller
@RequiredArgsConstructor
public class LogDemoController {
private final LogDemoService logDemoService;
private final MyLogger myLogger; // myLogger๋ฅผ ๋ง์น ํด๋์ค์ฒ๋ผ ์ฌ์ฉํ๊ณ ์๋ค.
@RequestMapping("log-demo")
@ResponseBody
public String logDemo(HttpServletRequest request) {
String requestURL = request.getRequestURL().toString();
myLogger.setRequestURL(requestURL); // ๋ฐ๋ก ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
myLogger.log("controller test");
logDemoService.logic("testId");
return "OK";
}
}
@Service
@RequiredArgsConstructor
public class LogDemoService {
private final MyLogger myLogger;
public void logic(String id) { // Provider๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
myLogger.log("service id = " + id);
}
}
@ ์ด๊ฒ ์ด๋ป๊ฒ ๊ฐ๋ฅํ๊ฑธ๊น?
์ด๋ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด(myLogger)๋ฅผ ์ฝ์์ฐฝ์ ์ฐ์ด๋ณด๋ฉด ์ด๋ป๊ฒ ๊ฐ๋ฅํ์ง ์ ์ ์๋ค.
System.out.println("myLogger = " + myLogger.getClass());
// myLogger = class hello.core.common.MyLogger$$EnhancerBySpringCGLIB$$b68b726d
CGLIB๋ผ๋ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ด ํด๋์ค๋ฅผ ์์๋ฐ์ "๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด"๋ฅผ ๋ง๋ค์ด์ ๋์ ์ฃผ์ ํ๋ค.
- @Scope ์ proxyMode = ScopedProxyMode.TARGET_CLASS) ๋ฅผ ์ค์ ํ๋ฉด ์คํ๋ง ์ปจํ ์ด๋๋ CGLIB ๋ผ๋ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์, MyLogger๋ฅผ ์์๋ฐ์ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค
- ๋ก๊ทธ๋ฅผ ์ฐ์ด๋ณด๋ฉด MyLogger๋ฅผ ์์๋ฐ์ MyLogger$$EnhancerBySpringCGLIB๊ฐ ์์ฑ๋จ์ ์ ์ ์๋ค.
- ๊ทธ๋ฆฌ๊ณ ์คํ๋ง ์ปจํ ์ด๋์ "MyLogger"๋ผ๋ ์ด๋ฆ์ผ๋ก ์ง์ง ๋์ ์ ์ด ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ฑ๋กํ๋ค.
- ac.getBean("myLogger", MyLogger.class)๋ก ์กฐํํด๋ ์ด ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๊ฐ ์กฐํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
- ์ฆ ์์กด๊ด๊ณ ์ฃผ์ ๋ํ ์ด ๊ฐ์ง ๊ฐ์ฒด๊ฐ ์ฃผ์ ๋๋ค.
๋ค์ ์๋ ๊ทธ๋ฆผ์ ์ดํด๋ณด์.
๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์์ฒญ์ด ์ค๋ฉด ๊ทธ๋ ๋ด๋ถ์์ ์ง์ง ๋น์ ์์ฒญํ๋ ์์๋ก์ง์ด ๋ค์ด์๋ค.
- ํด๋ผ์ด์ธํธ๊ฐ myLogger.logic()์ ํธ์ถํ๋ฉด ์ค๊ฐ์ ์๋ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด์ logic()์ด ํธ์ถ๋๋ค.
- ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ request ์ค์ฝํ์ ์ง์ง myLogger.logic()์ ํธ์ถํ๋ค.
- ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ์ ์์๋ฐ์ ๋ง๋ค์๊ธฐ์, ํด๋ผ์ด์ธํธ ์ ์ฅ์์ ํ๋ก์์ ์กด์ฌ๋ฅผ ๋ชฐ๋ผ๋ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์๋ค. (๋คํ์ฑ)
- ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์๋ณธ์ด requset ์ค์ฝํ๋ ๋ง๋ ์ ํ ์๊ด์๋ค. ๋ด๋ถ์๋ ๋จ์ํ ์์ ๋ก์ง๋ง ์๊ณ , ์ฑ๊ธํค์ฒ๋ผ ๋์ํ๋ค.
@ ํ๋ก์์ ์ฅ์
Scope์ ํ๋ก์ ๋ชจ๋๋ฅผ ์ง์ ํด์ฃผ๋ฉด, ์๋์ ๊ฐ์ ๋์์ด ์ผ์ด๋๋ค.
- CGLIB๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํด, ๋ด ํด๋์ค๋ฅผ ์์๋ฐ์ ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฃผ์ ํ๋ค.
- ์ด ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ์ค์ ์์ฒญ์ด ์ค๋ฉด ๊ทธ๋ ๋ด๋ถ์์ ์ค์ ๋น์ ์์ฒญํ๋ ์์ ๋ก์ง์ด ๋ค์ด๊ฐ์๋ค.
- ๊ฐ์ง ํ๋ก์ ๊ฐ์ฒด๋ ๋ง ๊ทธ๋๋ก ๊ฐ์ง์ด๊ธฐ์ ์ค์ ๊ฐ์ฒด์ scope์๋ ์ ํ ์๊ด์๋ค. ์ฑ๊ธํค ์ค์ฝํ๋ก ์ฌ์ฉ๋๋ค.
์ด๋ ๊ฒ ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ฉด์ ์๋์ ๊ฐ์ ์ฅ์ ์ ์ป์ ์ ์๋ค.
- ํ๋ก์ ๊ฐ์ฒด ๋๋ถ์ ํด๋ผ์ด์ธํธ๋ ๋ง์น ์ฑ๊ธํค ๋น์ ์ฌ์ฉํ๋ฏ requset scope๋ฅผ ์ด์ฉํ ์ ์๋ค.
- ์ด๋ ธํ ์ด์ ์ค์ ๋ณ๊ฒฝ๋ง์ผ๋ก ์๋ณธ ๊ฐ์ฒด๋ฅผ ํ๋ก์ ๊ฐ์ฒด๋ก ๋์ฒดํ ์ ์๋ค. (๋คํ์ฑ๊ณผ DI ์ปจํ ์ด๋์ ์ฅ์ )
- ์น ์ค์ฝํ๊ฐ ์๋๋๋ผ๋, ํ๋ก์๊ฐ ํ์ํ ๊ฒฝ์ฐ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
์ฌ์ค Provider๋ฅผ ์ฌ์ฉํ๋ , ํ๋ก์๋ฅผ ์ฌ์ฉํ๋ ํ์ํ ๊ฒ์ ์ง์ง ๊ฐ์ฒด ์กฐํ๋ฅผ ๊ผญ ํ์ํ ์์ ๊น์ง ์ง์ฐ์ฒ๋ฆฌ ๊ฐ๋ฅํ๊ฒ ํ๋ค๋ ์ ์ด๋ค. ์ด๋ ์์ฒญ์ด ๋ค์ด์ฌ ๋ ๋น์ ์์ฑํ๋ ์น ์ค์ฝํ๋ฅผ ๋ง์น '์ฑ๊ธํค์ ์ฌ์ฉํ๋ ๊ฒ' ์ฒ๋ผ ๋ง๋ค์ด ์ฃผ๋ ๊ฒ์ด์ง, ๊ฒฐ๊ตญ์๋ ๋ค๋ฅด๊ฒ ๋์ํ๋ค๋ ๊ฑธ ์ ์ํ์.
๋ํ ํ๋ก์๋ฅผ ์ฌ์ฉํด์ ์ด๋ ๊ฒ ํน์ํ Scope๋ฅผ ๋๋ฌด ๋ง์ด ๋ง๋ค๊ฒ ๋๋ฉด ์ ์ง๋ณด์๊ฐ ์ด๋ ค์์ง๋ค๋ ๊ฑธ ๋ช ์ฌํ์.
'๐ฑ Spring Framework > Spring Core' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
ํ ๋น์์คํ๋ง#2 ์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ์ ์ค๋ธ์ ํธ ์ค์ฝํ (0) | 2021.08.14 |
---|---|
ํ ๋น์ ์คํ๋ง#1 ์ค๋ธ์ ํธ์ ์์กด๊ด๊ณ (0) | 2021.08.14 |
#10 ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ (0) | 2021.08.03 |
#9 ์์กด๊ด๊ณ ์๋์ฃผ์ ์์ ์๊ธฐ๋ ๋ฌธ์ (+Lombok ์๊ฐ) (0) | 2021.08.03 |
#8 ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋์ฃผ์ (0) | 2021.08.02 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev