Spring / Bean Scope
by rlaehddnd0422๋น ์ค์ฝํ
: ๋น์ด ์ปจํ ์ด๋ ๋ด๋ถ์์ ์กด์ฌํ ์ ์๋ ๋ฒ์
์ง๊ธ๊น์ง ์คํ๋ง ๋น์ด ์คํ๋ง ์ปจํ ์ด๋์ ์์๊ณผ ํจ๊ป ์์ฑ๋์๋ค๊ฐ ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ์ ์ง๋๋ค๊ณ ๋ฐฐ์ ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ผ๋ก ์์ฑ๋๊ธฐ ๋๋ฌธ์ด๋ค.
์คํ๋ง ๋น์๋ ์ฑ๊ธํค๊ณผ ํ๋กํ ํ์ ์ด ์๋ค.
์ฑ๊ธํค : ๊ธฐ๋ณธ ๋น, ์คํ๋ง ์ปจํ ์ด๋์ ์์๊ณผ ํจ๊ป ์์ฑ -> ์ปจํ ์ด๋ ์ข ๋ฃ์ง์ ์ ์๋ฉธ๋จ.
ํ๋กํ ํ์ : ๋น์ ์์ฑ๊ณผ ์์กด๊ด๊ณ ์ฃผ์ ๊น์ง๋ง ์ ์ง๋๋ ๋น. ์ด ์ดํ์๋ ์ปจํ ์ด๋์์ ๊ด๋ฆฌ๋์ง ์๋๋ค.
๋น ์ค์ฝํ๋ @Scope๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ด ์ง์ ํ ์ ์๋ค.
@Scope("prototype") -> ํ๋กํ ํ์ ์ค์ฝํ
@Scope("singleton") -> ์ฑ๊ธํค ์ค์ฝํ
@Component๋ฅผ ์ด์ฉํ ์๋๋ฑ๋ก
@Scope("prototype")
@Component
public class HelloBean{}
์๋ ๋ฑ๋ก
@Scope("prototype")
@Bean
ProtoTypeBean HelloBean()
{
return new HelloBean();
}
์ง๊ธ๊น์ง๋ ๊ณ์ ์ฑ๊ธํค ์ค์ฝํ๋ฅผ ์ฌ์ฉํด๋ณด์์ผ๋, ํ๋กํ ํ์ ์ค์ฝํ๋ฅผ ์ฌ์ฉํด๋ณด์
ํ๋กํ ํ์ ์ค์ฝํ
์ฑ๊ธํค์ ๊ฒฝ์ฐ ํญ์ ๊ฐ์ ์ธ์คํด์ค์ ์คํ๋ง ๋น์ ๋ฆฌํดํ๋ค.
ํ์ง๋ง ํ๋กํ ํ์ ์ ํญ์ ์๋ฌ์ด ์ธ์คํด์ค๋ฅผ ์์ฑํด์ ๋ฆฌํดํ๋ค. ( ์๋ฐํ ๋งํ๋ฉด ์ธ์คํด์ค ์์ฑ ํ ์์กด๊ด๊ณ ์ฃผ์ ๊น์ง ๋ง์น ํ ๋ฆฌํด )
1. ํ๋กํ ํ์ ์ค์ฝํ์ ๋น์ ์ปจํ ์ด๋์ ์์ฒญ
2. ์ด ์์ ์ ํญ์ ์๋ก์ด ํ๋กํ ํ์ ๋น์ ์์ฑํ๊ณ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ค.
3. ํด๋ผ์ด์ธํธ์ ๋ฆฌํด
4. ๋ฆฌํด ์ดํ์๋ ์ปจํ ์ด๋์์ ๊ด๋ฆฌํ์ง ์๋๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ ์ปจํ ์ด๋๋ ํ๋กํ ํ์ ๋น์ ์์ฑ -> DI -> ์ด๊ธฐํ ๊น์ง๋ง ์ฒ๋ฆฌ.
๋น์ ๋ฆฌํดํ์๋ ์ปจํ ์ด๋์์ ๊ด๋ฆฌ X!!
๊ทธ๋์ @PreDestroy๊ฐ์ ์ข ๋ฃ ๋ฉ์๋๊ฐ ํธ์ถ๋์ง ์์.
TestCode
package hello.core.scope;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class PrototypeTest {
@Test
void prototypeBeanTest()
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ProtoTypeBean.class);
System.out.println("find prototypeBean1");
ProtoTypeBean protoTypeBean1 = ac.getBean(ProtoTypeBean.class);
System.out.println("find prototypeBean2");
ProtoTypeBean protoTypeBean2 = ac.getBean(ProtoTypeBean.class);
System.out.println("protoTypeBean1 = " + protoTypeBean1);
System.out.println("protoTypeBean2 = " + protoTypeBean2);
Assertions.assertThat(protoTypeBean1).isNotSameAs(protoTypeBean2);
ac.close();
}
@Scope("prototype")
static class ProtoTypeBean
{
@PostConstruct
public void init()
{
System.out.println("ProtoTypeBean.init");
}
@PreDestroy
public void destroy()
{
System.out.println("ProtoTypeBean.destroy");
}
}
}
๊ฐ์ฒด์ ๋ณด๋ฅผ ๋ณด๋ฉด ์๋ก ๋ค๋ฅธ ์ฃผ์๋ฅผ ๊ฐ์ง๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ํ๋กํ ํ์ ๋น์ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์์ฑ๊ณผ ์์กด๊ด๊ณ ์ฃผ์ ๊ทธ๋ฆฌ๊ณ ์ด๊ธฐํ ๊น์ง๋ง ๊ด์ฌํ๊ณ , ๋๋ ๊ด๋ฆฌํ์ง ์๋๋ค. ๋ฐ๋ผ์ ํ๋กํ ํ์ ๋น์ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์ข ๋ฃ๋ ๋ @PreDestroy ๊ฐ์ ์ข ๋ฃ ๋ฉ์๋๊ฐ ์ ํ ์คํ๋์ง ์๋๋ค.
ํ๋กํ ํ์ ๋น์ ํน์ง
1. ์ปจํ ์ด๋์ ์์ฒญ๋ ๋ ๋ง๋ค ์๋ก ์์ฑ๋๋ค.
2. ์ปจํ ์ด๋๋ ํ๋กํ ํ์ ๋น์ ์์ฑ, DI, ์ด๊ธฐํ๊น์ง๋ง ๊ด์ฌํ๋ค.
3. ์ข ๋ฃ๋ฉ์๋๊ฐ ํธ์ถ๋์ง ์์
4. ๊ทธ๋์ ํ๋กํ ํ์ ๋น์ ํ๋กํ ํ์ ๋น์ ์กฐํํ ํด๋ผ์ด์ธํธ๊ฐ ๊ด๋ฆฌํด์ผ ํ๋ค.
ํ๋กํ ํ์ - ์ฑ๊ธํค ํจ๊ป ์ฌ์ฉ ์ ๋ฌธ์ ์
๋ค์๊ณผ ๊ฐ์ ์ํฉ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณด์.
1. SpringContainer๋ด๋ถ์ SingletonBean, ProtoTypeBean ์์ฑ
2. Singleton -> ProtoTypeBean ์์กด @Autowired
3. ClientA๊ฐ login() ํธ์ถํ ๋ค ClientB๊ฐ logic()์ ํธ์ถํ ๋ค์ count ๊ฐ์ ๋ช์ผ๊น?
TestCode
package hello.core.scope;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SingletoneWithProtoTypeTest {
@Test
void singleWithProto()
{
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class, ProtoTypeBean.class);
SingletonBean bean = ac.getBean(SingletonBean.class);
SingletonBean bean2 = ac.getBean(SingletonBean.class);
int count1 = bean.logic();
int count2 = bean2.logic();
System.out.println("count1 = " + count1);
System.out.println("count2 = " + count2);
}
@Scope("singleton")
static class SingletonBean
{
private final ProtoTypeBean protoTypeBean;
@Autowired
public SingletonBean(ProtoTypeBean protoTypeBean) {
this.protoTypeBean = protoTypeBean;
}
public int logic()
{
protoTypeBean.addCount();
return protoTypeBean.getCount();
}
@PostConstruct
public void init()
{
System.out.println("SingletonBean.init");
}
@PreDestroy
public void destroy()
{
System.out.println("SingletonBean.destroy");
}
}
@Scope("prototype")
static class ProtoTypeBean
{
private int count = 0;
public void addCount()
{
count++;
}
public int getCount()
{
return this.count;
}
@PostConstruct
public void init()
{
System.out.println("ProtoTypeBean.init");
}
@PreDestroy
public void destroy()
{
System.out.println("ProtoTypeBean.destroy");
}
}
}
ํด๋ผ์ด์ธํธB๋ SingletoneBean์ ์ปจํ ์ด๋์ ์์ฒญํด์ ๋ฐ๋๋ค. ์ฑ๊ธํค์ด๋ฏ๋ก ํญ์ ๊ฐ์ SingletonBean์ด ๋ฐํ๋๋ค.
์ฌ๊ธฐ์ ์ค์ํ ์ ์ SingletonBean์ด ๋ด๋ถ์ ๊ฐ์ง๊ณ ์๋ ProtoTypeBean
์ ์ด๋ฏธ Client A์์ ์ฃผ์ ์ด ๋๋ ๋น์ด๋ค. ์ฃผ์ ์์ ์ ์คํ๋ง ์ปจํ ์ด๋์ ์์ฒญํด์ ํ๋กํ ํ์ ๋น์ด ์๋ก ์์ฑ์ด ๋ ๊ฒ์ด์ง, ์ฌ์ฉํ ๋๋ง๋ค ์๋ก ์์ฑ๋๋ ๊ฒ์ด ์๋๋ค. ๋ฐ๋ผ์ ClientB๋ A๊ฐ ์์ฒญํ count๊ฐ์์ 1 ์ฆ๊ฐํ์ฌ 2๊ฐ ๋๋ค.
์คํ๋ง์ ์ผ๋ฐ์ ์ผ๋ก ์ฑ๊ธํค ๋น์ ์ฌ์ฉํ๋ฏ๋ก ์ฑ๊ธํค ๋น์ด ํ๋กํ ํ์ ๋น์ ์ฌ์ฉํ๊ฒ ๋จ.
๊ทธ๋ฐ๋ฐ ์ฑ๊ธํค ๋น์ ์์ฑ ์์ ์๋ง ์์กด๊ด๊ณ ์ฃผ์ ์ ๋ฐ๊ธฐ ๋๋ฌธ์, ํ๋กํ ํ์ ๋น์ด ์๋ก ์์ฑ๊ธฐ๋ ํ์ง๋ง, ์ฑ๊ธํค ๋น๊ณผ ํจ๊ป ๊ณ์ ์ ์ง๋๋ค๋ ๊ฒ์ด ๋ฌธ์ ๋ค.
Provider๋ฅผ ์ด์ฉํ ์์กด๊ด๊ณ ์กฐํ (DL)
์ฐ์ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์ฑ๊ธํค ๋น์ด ํ๋กํ ํ์ ์ ์ฌ์ฉํ ๋๋ง๋ค ์คํ๋ง ์ปจํ ์ด๋์ ์๋ก ์์ฒญํ๋ ๊ฒ์ด๋ค
์ฝ๋๋ก ์์๋ณด์
@Scope("singleton")
static class ClientBean
{
@Autowired private ApplicationContext ac;
public int logic()
{
PrototypeBean bean = ac.getBean(PrototypeBean.class);
bean.addcount();
return bean.getCount();
}
}
์คํํด๋ณด๋ฉด ac.getBean์ ํตํด ํ๋กํ ํ์ ๋น์ ํญ์ ์๋ก ์์ฑํ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์์กด๊ด๊ณ๋ฅผ ์ธ๋ถ์์ ์ฃผ์ ๋ฐ๋ ๊ฒ ์๋๋ผ ์ง์ ํ์ํ ์์กด๊ด๊ณ๋ฅผ ์ฐพ๋ ๊ฒ์ DL(์์กด๊ด๊ณ ์กฐํ)๋ผ ํ๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ Application context ์ ์ฒด๋ฅผ ์ฃผ์ ๋ฐ๊ฒ ๋๋ฉด, ์ปจํ ์ด๋์ ์ข ์์ ์ธ ์ฝ๋๊ฐ ๋๊ณ , ๋จ์ ํ ์คํธ๊ฐ ์ด๋ ค์์ง.
์ง๊ธ ํ์ํ ๊ธฐ๋ฅ : ์ง์ ํ ํ๋กํ ํ์ ๋น์ ์ปจํ ์ด๋์์ ๋์ ์ฐพ์์ฃผ๋ ๋ฑ DL์ ๋์ ๊ธฐ๋ฅ๋ง ์ ๊ณตํ๋ ๋ฌด์ธ๊ฐ๊ฐ ํ์.
โถ๏ธ ObjectFactory, ObjectProvider
์ง์ ํ ๋น์ ์ปจํ ์ด๋์์ ๋์ ์ฐพ์์ฃผ๋ DL ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ด ๋ฐ๋ก ObjectProvider
ObjectProvider๋ฅผ ์ฌ์ฉํ ์์
@Scope("singleton")
static class ClientBean
{
// @Autowired private ApplicationContext ac;
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic()
{
// PrototypeBean bean = ac.getBean(PrototypeBean.class);
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addcount();
return prototypeBean.getCount();
}
}
์คํํด๋ณด๋ฉด prototypeBeanProvider.getObject()๋ฅผ ํตํด์ ํญ์ ์๋ก์ด ํ๋กํ ํ์ ๋น์ด ์์ฑ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
ObejctProvider์ getObejct()๋ฅผ ํธ์ถํ๋ฉด ๋ด๋ถ์์๋ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํตํด ํด๋น ๋น์ ์ฐพ์์ ๋ฐํํ๋ค.
ObejctFactory ๋ํ ๋ง์ฐฌ๊ฐ์ง
@Scope("singleton")
static class ClientBean
{
// @Autowired private ApplicationContext ac;
// @Autowired
// private ObjectProvider<PrototypeBean> prototypeBeanProvider;
@Autowired
private ObjectFactory<PrototypeBean> prototypeBeanObjectFactory;
public int logic()
{
// PrototypeBean bean = ac.getBean(PrototypeBean.class);
// PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
PrototypeBean prototypeBean = prototypeBeanObjectFactory.getObject();
prototypeBean.addcount();
return prototypeBean.getCount();
}
}
์ฐจ์ด์
ObjectFactory : ๊ธฐ๋ฅ์ด ๋จ์, ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ ์์, ์คํ๋ง์ ์์กด
ObjectProvider : ObjectFactory ์์, ์ต์ , ์คํธ๋ฆผ ์ฒ๋ฆฌ๋ฑ ํธ์ ๊ธฐ๋ฅ์ด ๋ง๊ณ , ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํ์ ์์, ์คํ๋ง์ ์์กด
์คํ๋ง ์ปจํ ์ด๋์ ์์กดํ์ง ์๋ ์๋ฐ ํ์ค DL๋ ์๋ค โถ๏ธ JSR-330 Provider
'๐ Backend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Spring / ์ง๊ธ๊น์ง ์ฌ์ฉํ ์ด๋ ธํ ์ด์ ์ ๋ฆฌ @ (0) | 2023.02.20 |
---|---|
Spring / Web ์ค์ฝํ (0) | 2023.02.13 |
Spring / ์คํ๋ง ๋น Life-cycle callback (0) | 2023.02.10 |
Spring / List,Map์ ์ด์ฉํ ๋์ผํ์ ๋น ์ฌ์ฉ, ์๋๊ณผ ์๋์ ์ฌ๋ฐ๋ฅธ ์ค๋ฌด ์ด์ ๊ธฐ์ค (0) | 2023.02.08 |
Spring / @Qualifier, @Primary (0) | 2023.02.07 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422