이번에는 프로토타입 스코프를 싱글톤 빈과 사용했을때의 문제점에 대하여 공부하였다.
스프링 컨테이너에 프로토타입 스코프의 빈을 요청하면 항상 새로운 객체 인스턴스를 생성하여 반환한다.
하지만 싱글톤 빈과 함께 사용할 때는 의도한 대로 동작하지 않으므로 주의해야 한다.
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.Scope;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SingletonWithPrototypeTest1 {
@Test
void prototypeFind(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
prototypeBean1.addCount();
Assertions.assertThat(prototypeBean1.getCount()).isEqualTo(1);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
prototypeBean2.addCount();
Assertions.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 = ");
}
}
}
코드로 보면 가상의 사용자 1 ,2 가 count라는 데이터를 증가시키는 메서드를 호출했을 때
다른 객체를 생성하기 때문에 count값이 1이 된다는 것을 테스트 하는 코드이다.
싱글톤 빈에서 프로토타입 빈 사용
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.Scope;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SingletonWithPrototypeTest1 {
@Test
void prototypeFind(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
prototypeBean1.addCount();
Assertions.assertThat(prototypeBean1.getCount()).isEqualTo(1);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
prototypeBean2.addCount();
Assertions.assertThat(prototypeBean2.getCount()).isEqualTo(1);
}
@Test
void singletonClientUsePrototype(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean clientBean1 = ac.getBean(ClientBean.class);
int count1 = clientBean1.logic();
Assertions.assertThat(count1).isEqualTo(1);
ClientBean clientBean2 = ac.getBean(ClientBean.class);
int count2 = clientBean2.logic();
Assertions.assertThat(count2).isEqualTo(2);
}
@Scope("singleton")
static class ClientBean{
private final PrototypeBean prototypeBean;
public ClientBean(PrototypeBean prototypeBean){
this.prototypeBean = prototypeBean;
}
public int logic(){
prototypeBean.addCount();;
int count = prototypeBean.getCount();
return count;
}
}
@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 = ");
}
}
}
새로운 클래스 ClientBean을 만들고 PrototypeBean을 의존한다.
먼저 ClientBean은 싱글톤이다.
스프링 빈에 등록되면서 생성자에 있는 PrototypeBean을 요청하는데
그때 스프링 컨테이너가 PrototypeBean을 만들어서 던져준다.
그때 만들어진 객체가 생성시점에 주입된다.
PrototypeBean의 메서드를 호출하면 이미 생성된 객체에서
같이 쓰게된다.
한마디로 스프링 컨테이너에서 새로운 요청을 받을 때마다 생성해주는 기능인데
처음 주입받을때만 들어와버린것이다.
프로토타입을 쓰는 이유가 전혀 없는 코드가 되어버린것이다.
'웹프로그래밍 > Spring 핵심 원리' 카테고리의 다른 글
51. 웹 스코프 (0) | 2021.10.14 |
---|---|
50. 프로토타입 스코프 - 싱글톤 빈과 함께 사용시 Provider로 문제 해결 (0) | 2021.09.09 |
48. 프로토타입 스코프 (0) | 2021.08.23 |
47. 빈 스코프란? (0) | 2021.08.23 |
46. 애너테이션 @PostConstruct, @PreDestroy (0) | 2021.08.20 |