※ 본 포스팅은 21.11.09에 게시된 글을 이전한 것 입니다.
1. 빈 스코프란?
지금까지 스프링 빈이 스프링 컨테이너 시작과 함께 생성되어서 스프링 컨테이너가 종료될 때까지 유지된다고 학습했다.
이는 스프링빈이 기본적으로 싱글톤 스코프로 생성되기 때문이다.
스프링은 다양한 스코프를 지원한다.
· 싱글톤 : 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프
· 프로토타입 : 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입까지만 관여하는 매우 짧은 범위의 스코프
· 웹 관련 스코프 :
- request : 웹 요청이 들어오고 나갈 때까지 유지되는 스코프
- session : 웹 세션이 생성되고 종료될 때까지 유지되는 스코프, 예를 들어 로그인 등에 쓰임
- application : 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프
#이런 식으로 지정할 수 있다.
@Scope("prototype")
2. 프로토타입 스코프
핵심은 스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지만 처리한다는 것이다. 그 후 관리는 하지 않는다.
결국 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에게 있다.
그래서 @PreDestroy같은 종료 메서드가 호출되지 않는다!!!!
1) 싱글톤 빈과 함께 사용 시 문제점
우리 생각은 프로토타입 빈은 조회할 때마다 매번 생성되어야 하는데 실제는 그러지 못했다.
clientBean은 싱글톤이므로, 보통 스프링 컨테이너 생성될 때 같이 생성되고 의존관계 주입도 발생한다.
의존 관계 주입 시점에 컨테이너에 프로토타입 빈을 요청한다.
후에 스프링 컨테이너는 프로토 타입 빈을 생성하여 반환한다.
이제 clientBean은 프로토타입 빈을 내부 필드에 보관하게 된다! (실제는 참조 값을 가지고 있다고 함)
clientBean은 싱글톤이므로 항상 같은 clientBean이 반환된다.
여기서도 마찬가지로 clientBean은 싱글톤이므로 항상 같은 clientBean이 반환된다.
clientBeandl 내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈이라는 점이 문제점이다.
주입 시점에 스프링 컨테이너에 요청해서 프로토타입 빈이 새로 생성된 것이지 사용할 때마다 새로 생성된 것이 아니다.
고로 우리의 의도와는 상당히 다르게 굴러가고 있는 것이다.
static class ClintBean{
private final PrototypeBean prototypeBean;
@Autowired
//이때 프로토타입 생성 및 호출 + 한번 호출 된다고 보면 돼
public ClintBean(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
}
2) Provider로 문제 해결
⑴스프링 컨테이너에 요청 : 가장 간단한 방법!! 사용할 때마다 스프링 컨테이너에 새로 요청하는 것이다.
static class ClientBean {
@Autowired
private ApplicationContext ac;
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
}
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class) : 을 통해 매번 프로토타입 빈을 생성한다.
의존관계를 외부에서 주입받는 것이 아니라. 직접 필요한 의존 관계를 찾는 것을 Dependency Lookup (DL) 의존 관계 조회 (탐색 )이라 한다. 하지만 이렇게 스프링 애플리케이션 컨텍스트를 전체 주입받게 되면, 스프링 컨테이너에 종속적인 코드가 되며 단위 테스트도 어려워진다.
그러므로 우리는 지정한 프로토타입 빈을 컨테이너에서 대신 찾아주는 그런 무언가가 필요한 것이다.
⑵ObjectFactory , ObjectProvider
이는 저장한 빈을 컨테이너에서 대신 찾아주는 DL 서비스를 제공한다.
static class ClintBean{
/**필드 주입*/
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanObjectProvider;
public int logic(){
PrototypeBean prototypeBean = prototypeBeanObjectProvider.getObject();
prototypeBean.addCount();
int count=prototypeBean.getCount();
return count;
}
}
간단하게 설명하면, 찾아주는 과정을 간단하게 그리고 대신 조회해 주는 대리자 정도로 생각하면 된다.
getObject()를 호출하면 프로토타입 빈이 생성되며 내부적으로는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.
※ 특징
ObjectFactory : 기능이 단순, 별도의 라이브러리 필요 없으며 스프링에 의존
ObjectProvider : 위의 상속. 편의 기능이 많고 별도의 라이브러리 필요 없으며 스프링에 의존
⑶ JSR-330 Provider
javax.inject.Provider라는 JSR-330 자바 표준을 사용하는 방법이다. 하지만 위 라이브러리를 gradle에 추가해야 한다.
자바 표준이며 기능이 단순하므로 단위 테스트를 만들거나 mock 코드를 만들기는 훨씬 쉽다.
static class ClintBean{
/**필드 주입*/
@Autowired
private Provider<PrototypeBean> provider;
public int logic(){
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count=prototypeBean.getCount();
return count;
}
}
provider.get() : 을 통해 새로운 프로토타입 빈이 생성되며 이를 호출했을 때 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.
※프로토타입 빈은 언제 사용하는가?
매번 사용할 때마다 의존 관계가 새로 주입된 새로운 객체가 필요하면 사용하면 된다.
하지만 싱글톤으로 대부분의 문제를 해결할 수 있어 실제로 프로토타입 빈을 사용할 일은 거의 없다.
결과적으로 우리가 원하는 방향으로 사용하기 위해서는 싱글톤빈에 의존관계를 주입하지 말고
DL을 사용하여 원할때 프로토타입 빈을 생성 할 수 있도록 한다!
Uploaded by
'📑 개발 이론 > 🌱 SPRING' 카테고리의 다른 글
스프링 핵심 원리 - 빈 스코프(2) (0) | 2023.06.26 |
---|---|
스프링 핵심 원리 - 빈 생명주기 콜백 (0) | 2023.06.26 |
스프링 핵심 원리 - 의존관계 자동주입 (0) | 2023.06.26 |
스프링 핵심 원리 - 컴포넌트 스캔 (0) | 2023.06.26 |
스프링 핵심 원리 - 싱글톤 (0) | 2023.06.17 |