빈으로써 존재할 수 있는 범위를 의미한다.(default는 싱글톤)
(빈 저장소에서 관리하는 범위)
싱글톤 빈을 조회하면 스프링 컨테이너에는 항상 같은 인터페이스의 스프링 빈을 반환
프로토타입 빈을 조회하면 스프링 컨테이너는 새로운 인스턴스를 생성해서 반환
주로 초기화까지 완료된 인스턴스를 받고 싶을 때 사용, 거의 사용하지 않는다.
Assertions.assertThat(singletonBean1).isSameAs(singletonBean2);
a.isSameAs(b)
는 a==b 를 의미
싱글톤 빈은 스프링 컨테이너 생성 시점에 초기화 메서드가 실행
프로토타입 빈은 스프링 컨테이너에서 빈을 조회할 때 생성되고 초기화 메서드도 실행
싱글톤 빈이 프로토타입 빈을 내부 필드로 가지고 있다고 가정.
싱글톤 빈이 프로토타입 빈의 참조를 가지고 있어 프로토타입의 생존주기가 싱글톤 빈 스코프와 같아진다.
@Scope("singleton")
class ClientBean {
private final PrototypeBean prototypeBean;
@Autowired
public ClientBean(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
public int login() {
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
의존관계를 외부에서 주입받는 것은 DI, 직접 찾아서 사용하는 것은 DL(dependency lookup)
class ClientBean {
public int logic() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);
PrototypeBean prototype = ac.getBean(PrototypeBean.class);
return prototype.getCount();
}
}
메소드를 실행할때 마다 직접 스프링 컨텍스트에서 해당 프로토타입 빈을 찾아 새로운 빈을 생성해 사용한다.
컨텍스트를 주입받으므로 스프링 종속적이고, 단위테스트도 쉽지 않다.
그래서 스프링 컨텍스트에서 직접 찾는 것보다 대신 찾아주는 DL 정도의 기능만 제공하는 무언가를 사용해야 한다.
@Autowired
private ObjectProvider<PrototypeBean> provider;
public int login() {
PrototypeBean prototypeBean = provider.getObject();
prototypeBean.addCount();
return prototypeBean.getCount();
}
ObjectProvider는 컨텍스트에서 해당 빈을 DL해주는, 스프링 의존적인 기능이지만 기능이 간단해서 괜찮다.
필요한 정도의 DL을 대신 해주는 느낌
ObjectFactory의 자식이 ObjectProvider
스프링에 의존하지 않는 330자바 표준을 사용하는 방식
gradle 추가 implementation 'javax.injdet:javax.inject:1'
import javax.inject.Provider;
@Autowired
private Provider<PrototypeBean> provider;
public int login() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
return prototypeBean.getCount();
}
ObjectProvider와 사용방법이 같다.