프로토타입 스코프에 대해서 알아보겠다.
프로토타입 스코프를 사용하면 원래는 빈이 싱글톤으로 등록이 된다. 하지만 프토로타입 스코프를 사용하면 싱글톤이 아니라 해당 빈을 부를때마다 초기화가 발생한다
public class PrototypeTest {
@Scope("prototype")
static class PrototypeBean {
public void use() {
System.out.println("사용!!");
}
@PostConstruct
public void init() {
System.out.println("init");
}
@PreDestroy
public void close() {
System.out.println("close");
}
}
@Test
public void prototypeTest() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class);
PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class);
PrototypeBean prototypeBean3 = ac.getBean(PrototypeBean.class);
System.out.println("prototypeBean1 : " + prototypeBean1);
System.out.println("prototypeBean1 : " + prototypeBean2);
System.out.println("prototypeBean1 : " + prototypeBean3);
ac.close()
}
}
이렇게 각 객체마다 주소가 달라진것이 보이며 getBean을 할때마다 init이 발생한것이 보인다.
그럼 싱글톤으로 하면 어떻게 나오느냐고 물어볼 수있다.
public class SingletonTest {
@Scope("singleton")
static class SingletonBean {
public void use() {
System.out.println("사용");
}
@PostConstruct
public void init() {
System.out.println("init");
}
@PreDestroy
public void close() {
System.out.println("close");
}
}
@Test
public void singletonTest() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class);
SingletonBean singletonBean1 = ac.getBean(SingletonBean.class);
SingletonBean singletonBean2 = ac.getBean(SingletonBean.class);
SingletonBean singletonBean3 = ac.getBean(SingletonBean.class);
System.out.println("SingletonBean1 : " + singletonBean1);
System.out.println("SingletonBean2 : " + singletonBean2);
System.out.println("SingletonBean3 : " + singletonBean3);
ac.close();
}
}
초기화는 한번만 일어났으며 주소가 모두 같다
추가적으로 singleton은 ac.close()를 호출하니 제대로 @Predestroy가 호출됐는데
prototype은 그러지 못한것을 볼 수 있다. 그 이유는
singleton은 스프링 컨테이너가 가지고 있다가 제거하는것도 책임져 주는 반면
prototype은 스프링 컨테이너가 생성, 의존관계 주입, 초기화 까지만 관여하고 빈을 클라이언트에게 냅다 던져놓고 "너 알아서 삭제해" 라고 하며 클라이언트에게 권한을 넘겨준다.
그래서 prototype에서는 @Predestroy 어노테이션이 제대로 동작하지 않은것이다.
또 다른 방법으로 ObjectProvider를 사용하는 방법이 있다.
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@SpringBootTest
public class PrototypeTest {
@Component
@Scope("prototype")
static class PrototypeBean {
public void use() {
System.out.println("사용!!");
}
@PostConstruct
public void init() {
System.out.println("init");
}
@PreDestroy
public void close() {
System.out.println("close");
}
}
ObjectProvider<PrototypeBean> prototypeBeanProvider;
@Autowired
public PrototypeTest(ObjectProvider<PrototypeBean> prototypeBeanProvider) {
this.prototypeBeanProvider = prototypeBeanProvider;
}
@Test
public void prototypeTest() {
PrototypeBean prototypeBean1 = prototypeBeanProvider.getObject();
PrototypeBean prototypeBean2 = prototypeBeanProvider.getObject();
PrototypeBean prototypeBean3 = prototypeBeanProvider.getObject();
System.out.println("prototypeBean1 : " + prototypeBean1);
System.out.println("prototypeBean1 : " + prototypeBean2);
System.out.println("prototypeBean1 : " + prototypeBean3);
}
}
결과값도 비슷한 것을 볼 수 있다. protoType을 직접 사용하는것 보다 Provider를 사용하는것이 테스트 코드 작성 및 유지보수 면에서 더 좋다고 한다.
그런데 난 아직 이해를 못하겠다. 나중에 이해를 할 날이 왔을 때 기억이 난다면 따로 작성해보겠다.
'Spring 공부' 카테고리의 다른 글
스프링 기본편 정리 6 (0) | 2023.11.01 |
---|---|
스프링 기본편 정리 4 (0) | 2023.11.01 |
스프링 기본편 정리3 (0) | 2023.11.01 |
스프링 기본편 정리2 (0) | 2023.11.01 |
스프링 기본편 정리1 (0) | 2023.11.01 |