
본 게시글은 김영한님의 스프링 핵심 원리 기본편을 정리한 글입니다.
이전 시간 싱글톤 빈과 프로토타입의 빈을 같이 사용하였을때 문제점을 알아봤는데 이를 해결하기위하여 어떻게 해야할 지 한 번 알아보자.
싱글톤 빈이 프로토타입을 사용할때마다 계속 다시 요청하여주면 된다고 한다.
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를 사용하면 된다.