이전에 싱글톤과 프로토타입 빈을 함께 사용하면 예상했던 것과는 다르게 동작했던것을 떠올릴 수 있습니다.
대부분의 빈은 싱글톤이고, 싱글톤 스코프의 빈은 스프링 컨테이너가 올라갈때 생성되고 의존관계를 전부 주입 받은 이후 스프링 컨테이너가 종료될 때 까지 유지됩니다.
다른 클라이언트가 같은 빈을 조회하면, 그 내부에 의존하고있는 프로토타입 빈은 의존관계 주입시에 이미 생성되어 유지되고 있기 때문에 우리가 예상했던것 과 다르게 같은 객체 인스턴스를 반환받게 됩니다.
자세한건 빈스코프 - 싱글톤과 프로토타입 을 다시 한번 읽어봅시다.
내용 요약 미리보기
Prototype 빈은 DL(Dependency Lookup)을 통해 호출시마다 조회해서 생성할 수 있다.
Provider가 DL기능을 편리하게 제공해주고 스프링이 제공하는 ObjectProvider, JSR - 330 자바 표준 Provider 가 있다.
Provider는 프로토타입을 사용하는 경우 뿐만 아니라 DL이 필요한 경우 언제든지 사용 가능하다.
실무에서는 대부분의 문제가 싱글톤 으로 해결되기 때문에 프로토타입을 잘 사용할 일이 없다고 한다.
앞으로 스프링이 제공하는 기능과 자바 표준으로 제공되는 기술이 겹칠 때 대부분 스프링이 제공하는 기술이 다양한 기능을 제공하고 편리하다. 그러나 특별히 스프링이 아닌 다른 컨테이너에서도 동작해야 한다면 자바 표준을 선택해야 한다.
빈 조회시마다 해당 빈에 의존하는 프로토타입 빈을 새로 생성해주고 싶다면 가장 간단한 방법은 로직을 호출할때
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
이러한 형식으로 프로토타입 빈을 조회해 주는 방법이 있습니다. 실행해보면 ac.getBean()을 통해 항상 새로운 프로토타입 빈이 생성되는 것을 확인 가능합니다.
DL
이렇게 의존관계를 외부에서 주입(DI) 받는 것이 아니라 직접 필요한 의존관계를 찾는 것을 Dependency Lookup 줄여서 DL 이라고 합니다.
이러한 DL기능을 제공해주는 두가지 Provider가 있습니다. ObjectProvider, JSR-330 Provider
ObjectProvider는 스프링에서 제공하는 프로바이더이고,
JSR-330 Provider는 자바 표준으로 제공되는 프로바이더 입니다.
하나씩 살펴봅시다.
지정한 빈을 스프링 컨테이너에서 대신 찾아주는 DL 서비스를 제공하는 것이 ObjectProvider 입니다.
과거에는 ObjectFactory 라는 것이 존재했었는데, 여기에 편의기능을 추가해서 만들어진 것이 Object Provider 입니다.
ObjectProvider 테스트 코드
ObjectProvider< Bean > 과 같은 형식으로 DL하기 원하는 빈을 지정하고, 이후 실행 로직에서 .getObject()를 통해 해당 빈을 찾아올 수 있습니다. 위 테스트에서는 프로토타입 빈을찾아왔기에 생성 - 의존관계 주입 - 초기화 메소드 호출 까지만 이루어지고 이후 스프링 컨테이너는 관리하지 않습니다.
ObjectProvider 테스트 결과
이렇게 두번 DL 할 때 마다 각각 프로토타입 빈이 생성되어 초기화 메소드를 실행하고, 객체 둘을 보면 다른 객체 인스턴스가 반환되는 것을 보아 원하는 대로 동작한 다는 사실을 알 수 있습니다.
마지막 방법은 javax.inject.Provider
라는 JSR-330 자바 표준을 사용하는 방법입니다. 이 경우는
build.gradle에 javax.inject:javax.inject:1
라이브러리를 추가해야 합니다.
자바 표준 Provider는 별도의 라이브러리가 필요하긴 하지만 자바 표준 기술이라 스프링 환경이 아니더라도 작동한다는 특징을 가지고 있습니다.
JSR - 330 Provider 테스트 코드
JSR - 330 Provider 테스트 결과
역시나 결과는 위와같이 이전과 동일하게 나오는 것을 확인 가능합니다.
정리
프로토타입 빈은 매번 사용할 때 마다 의존관계 주입이 완료된 새로운 객체가 필요하면 사용하면 됩니다. 그러나 실무에서는 대부분의 문제가 싱글톤 빈으로 해결되기 때문에 프로토타입 빈을 직접 사용하는 일은 드물다고 합니다.
또한 Provider는 프로토타입을 사용하는 경우 뿐만 아니라 DL이 필요한 경우는 언제든지 사용 가능합니다.
🌱 두개의 Provider 중에 어떤것을 사용해야 할까?
스프링에서 제공하는 ObjectProvider와 자바 표준 Provider 중 어떤것을 사용해야할까 하는 고민이 생길 수 있습니다.
스프링에서 제공하는 ObectProvider는 라이브러리 설치가 필요없고 DL을 위한 다양한 편의 기능들을 제공해주기 때문에 편리합니다. 그러나 코드를 스프링이 아닌 다른 컨테이너에서도 실행시켜야한다면 자바 표준 Provider를 사용해야 합니다.
스프링을 사용하다보면 여러가지 부분에서 자바의 표준과 스프링에서 제공하는 기능이 겹치는 경우가 많을텐데, 이러한 경우 대부분 스프링이 더 다양하고 편리한 기능을 제공하기 때문에 특별히 다른 컨테이너를 사용할 일이 없다면 스프링이 제공하는 기능을 사용합시다.
참고