본 게시글은 김영한님의 스프링 핵심 원리 기본편을 정리한 글입니다.
이전 시간 싱글톤 빈과 프로토타입의 빈을 같이 사용하였을때 문제점을 알아봤는데 이를 해결하기위하여 어떻게 해야할 지 한 번 알아보자.
싱글톤 빈이 프로토타입을 사용할때마다 계속 다시 요청하여주면 된다고 한다.
public class PrototypeProviderTest {
@Test
void providerTest(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
ClientBean bean = ac.getBean(ClientBean.class);
int count1= bean.logic();
Assertions.assertThat(count1).isEqualTo(1);
ClientBean bean2 = ac.getBean(ClientBean.class);
int count2= bean.logic();
Assertions.assertThat(count2).isEqualTo(1);
}
static class ClientBean{
@Autowired
private ApplicationContext ac; DL -> DependencyLookup
public int logic(){
PrototypeBean bean = ac.getBean(PrototypeBean.class);
bean.addCount();
return bean.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");
}
@PreDestroy
public void destroy(){
System.out.println("PrototypeBean.destroy");
}
}
여기서 우리가 봐야할 것은 다음 코드이다.
@Autowired
private ApplicationContext ac; DL -> DependencyLookup
public int logic(){
PrototypeBean bean = ac.getBean(PrototypeBean.class);
bean.addCount();
return bean.getCount();
}
여기서 여기서 이전에는 Autowired
로 PrototypeBean
과 연결하여 사용을 햇었는데 이번에는 스프링 컨테이너를 의존관계를 부여하여줬다 이러한 것은 DL(Dependency Lookup)
의존관계 조회(탐색) 이라고 한다고 한다.
DL : 의존관계 조회(탐색)
- DL(Dependency Lookup) : 의존대상(사용할 객체)을 검색(lookup)을 통해 반환받는 방식
- 내가 직접 필요한 의존관계를 찾는 것.
ac.getBean(PrototypeBean.class);
을 통하여서 직접 찾게 되었다.- 그치만
ApplicationContext
를 주입받으면 컨테이너에 종속적인 코드가 된다고 한다. -> 이렇게 되면 단위테스트가 어려운...- 이 단점을 해결하기위해서는 컨테이너에서 우리가 원하는 프로토타입의 빈을 찾기만 하면 된다.
위에서 얘기했듯이 내가 찾고싶은 빈을 컨테이너에서 대신 찾아주는 DL 서비스를 ObjectProvider
가 제공을 하여준다. 옛날에는 ObjectFactory
가 있었는데 여기에 기능을 추가한것인 ObjectProvider
가 만들어졌다고 한다.
static class ClientBean{
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanObjectProvider; ObjectProvider 스프링에 의존
public int logic(){
PrototypeBean prototypeBean = prototypeBeanObjectProvider.getObject();
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
ObjectFactory : 기능이 단순하고 별도의 라이브러리가 없음, 스프링에 의존함
ObjectProvider : ObjectFactory의 상속,옵션, 스트림 처리등 편의 기능이 많고, 별도의 라이브러리 필요 없음, 스프링에 의존
이전 코드와 비교하였을때 이제 DL을 ObjectProvider<PrototypeBean>을 통하여서 조회를 하여주고 밑에서 getObject를 활용하여서 빈을 반환시켰다.
그치만... 이 ObjectProvider와 ObjectFactory는 스프링에서 의존 기능이다. 그말인즉슨 다른 프레임워크에서는 이 기능을 활용하기에는 어려울 거 같다.
위 마지막에서 언급하듯이 ObjectProvider
는 스프링에 의존적이다. 그래서 자바 표준으로도 Provider
라는 기능을 제공한다. 위 기능은 javax.inject.Provider
를 import하면 된다.
static class ClientBean{
@Autowired
private Provider<PrototypeBean> prototypeBeanProvider; // Provider 자바 표준이므로 다른 프레임워크에서도 사용가능, get()하나로 되게 단순
public int logic(){
PrototypeBean prototypeBean = prototypeBeanProvider.get();
prototypeBean.addCount();
return prototypeBean.getCount();
}
}
Provider
를 통하여서는get()
을 활용하여DL
을 하게 된다.- 별도의 라이브러리가 필요하다.
- 스프링에 의존적이지 않아 다른 프레임워크에서도 사용이 가능하다.
오늘 찾아보게 이렇게 3가지의 방법으로 각각의 빈 스코프가 겹치게 될때 해결하는것을 보게 되었는데 결론적으로는 나중에 사용하게 될 것은 Provider
를 주로 사용하게 될 거 같다. 강의에서는 마지막에 정리를 하실때 이런 말씀을 해주셨다.
프로토타입 빈을 언제 사용할지 한 번 생각을 해보면 DI가 완료된 새로운 객체가 필요하면 사용하게 된다. 그런데 실무에서는 개발을 하게 되었을때 싱글톤 빈으로 대부분의 문제를 해결할 수 있기 때문에 프로토타입 빈을 직접적으로 사용하는 일은 매우 드물게 된다.
DL이 필요한 경우에는 언제든지Provider
나ObjectProvider
를 사용하면 된다.