clientBean이 프로토타입 빈을 내부 필드에 보관한다. 즉, 참조값을 보관하고 해당 빈을 관리한다.
클라이언트 A가 clientBean을 스프링 컨테이너에 요청한다. 싱글턴이므로 항상 같은 clientBean이 반환된다.
클라이언트 A가 clientBean.logic()을 호출한다.
호출된 clientBean은 프로토타입 빈의 addCount()를 호출해서 증가시키고, count는 1이 된다.
클라이언트 B가 clientBean을 스프링 컨테이너에 요청하고 싱글턴이므로 같은 clientBean을 받는다.
clientBean이 내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈이다.
주입 시점에 스프링 컨테이너에 요청할 때마다 프로토타입이 생성되는 것이지 사용할 때마다 생성되는 것이 아니다.
클라이언트 B가 clinetBean.logic()을 호출한다.
clientBean은 addCount()를 호출해서 count를 증가시키고 count는 2가 된다.
public class SingletonWithPrototypeTest1 {
@Test
void singletonClientUsePrototype() {
// ClientBean, PrototypeBean 둘 다 컴포넌트 스캔을 해줘야 빈으로 등록된다.
ApplicationContext ac =
new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.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);
}
}
}
테스트가 정상적으로 통과되었다.
ClientBean은 생성 시점에만 PrototypeBean을 주입받는다. 즉, 싱글턴 빈은 생성 시점에만 의존 관계 주입을 받기 때문에 프로토타입 빈 자체는 새로 생성되어도 싱글톤 빈과 라이프 사이클이 함께 유지된다.
만약 logic()을 호출 할 때마다 새로운 프로토타입을 주입받고 싶다면 어떻게 해야 할까? 다음 장에서 살펴보자.