<aside> ❗
[스프링은 다음과 같은 다양한 스코프를 지원한다.]
[웹 관련 스코프]
[컴포넌트 스캔 자동 등록]
@Scope("prototype")
@Component
public class HelloBean() {}
[수동 등록]
@Scope("prototype")
@Bean
public PrototypeBean helloBean() {
return new HelloBean();
}
</aside>
<aside> ❗
[싱글톤 빈 요청]
public class SingletonTest {
@Test
void singletonBeanFind() {
// 컴포넌트 클래스를 인자로 전달하면, 컴포넌트 스캔 대상이 되어 등록이 된다.
// 그래서 @Component를 작성하지 않아도 됨
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class);
SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
System.out.println("singletonBean1 = " + singletonBean1);
System.out.println("singletonBean2 = " + singletonBean2);
assertThat(singletonBean1).isSameAs(singletonBean2);
ac.close();
}
@Scope("singleton")
static class SingletonBean {
@PostConstruct
public void init() {
System.out.println("SingletonBean.init");
}
@PreDestroy
public void destroy() {
System.out.println("SingletonBean.close");
}
}
}
/*
출력 결과
SingletonBean.init
singletonBean1 = hello.core.scope.SingletonTest$SingletonBean@54e041a4
singletonBean2 = hello.core.scope.SingletonTest$SingletonBean@54e041a4
SingletonBean.close
*/
[프로토타입 빈 요청 1]
[프로토타입 빈 요청 2]
public class PrototypeTest {
@Test
void prototypeBeanFind() {
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);
// @PreDestroy가 동작하지 않으므로 클라이언트가 직접 호출해서 처리해야한다.
protoTypeBean1.destroy();
protoTypeBean2.destroy();
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");
}
}
}
/*
출력 결과
find protoTypeBean1
ProtoTypeBean.init
find protoTypeBean2
ProtoTypeBean.init
protoTypeBean1 = hello.core.scope.PrototypeTest$ProtoTypeBean@a8ef162
protoTypeBean2 = hello.core.scope.PrototypeTest$ProtoTypeBean@2eea88a1
*/
new AnnotationConfigApplicationContext(SingletonBean.class)
처럼
인자로 클래스를 직접 넘겨줄 경우, 해당 클래스는 컴포넌트 스캔 대상이 되어 등록됨[프로토타입 빈의 특징 정리]
</aside>
<aside> ❗
[스프링 컨테이너에 프로토타입 빈 직접 요청 1]
결과적으로 프로토타입 빈(0x1)의 count는 1이 된다.
[스프링 컨테이너에 프로토타입 빈 직접 요청 2]
결과적으로 프로토타입 빈(x02)의 count는 1이 된다.
public class SingletonWithPrototypeTest1 {
@Test
void protoTypeFind() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
prototypeBean1.addCount();
assertThat(prototypeBean1.getCount()).isEqualTo(1);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
prototypeBean2.addCount();
assertThat(prototypeBean2.getCount()).isEqualTo(1);
}
@Scope("prototype")
static class PrototypeBean {
private int count = 0;
public void addCount() {
count++;
}
public int getCount() {
return count;
}
@PostConstruct
public void init() {
System.out.println("PrototypeBean.init " + this);
}
@PreDestroy
public void destroy() {
System.out.println("PrototypeBean.destroy " + this);
}
}
}
[싱글톤에서 프로토타입 빈 사용1]
[싱글톤에서 프로토타입 빈 사용2]
[싱글톤에서 프로토타입 빈 사용3]
[정리]
public class SingletonWithPrototypeTest1 {
@Test
void singletonClientUserProtoType() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ProtoTypeBean.class, ClientBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
assertThat(count2).isEqualTo(2);
}
@Scope("singleton")
static class ClientBean {
private final ProtoTypeBean protoTypeBean;
@Autowired
public ClientBean(ProtoTypeBean protoTypeBean) {
// 생성 시점에 프로토타입빈이 등록됨
this.protoTypeBean = protoTypeBean;
}
public int logic() {
// 생성 시점에 등록된 프로토타입을 계속 사용
protoTypeBean.addCount();
return protoTypeBean.getCount();
}
}
@Scope("prototype")
static class ProtoTypeBean {
private int count = 0;
public void addCount() {
count++;
}
public int getCount() {
return count;
}
@PostConstruct
public void init() {
System.out.println("PrototypeBean.init " + this);
}
@PreDestroy
public void destroy() {
System.out.println("PrototypeBean.destroy " + this);
}
}
}
[참고]
</aside>
<aside> ❗
[스프링 컨테이너에 요청]
@Scope("singleton")
static class ClientBean {
private final ProtoTypeBean protoTypeBean;
@Autowired
ApplicationContext ac;
public int logic() {
ProtoTypeBean protoTypeBean
= ac.getBean(ProtoTypeBean.class);
protoTypeBean.addCount();
return protoTypeBean.getCount();
}
}
<aside> ❗
</aside>
<aside> ❗
</aside>
<aside> ❗
</aside>
<aside> ❗
</aside>
<aside> ❗
</aside>
<aside> ❗
</aside>