싱글톤 빈과 프로토타입 빈을 함께 사용할 때, 어떻게 하면 사용할 때 마다 항상 새로운 프로토타입 빈을 생성할 수 있을까?
스프링 컨테이너에 요청
가장 간단한 방법은 싱글톤 빈이 프로토타입을 사용할 때 마다 스프링 컨테이너에 새로 요청하는 것이다.
ac.getBean()
을 통해서 항상 새로운 프로토타입 빈이 생성되는 것을 확인할 수 있다.ObjectFactory, ObjectProvider
지정한 빈을 컨테이너에서 대신 찾아주는 DL서비스를 제공하는 것이 바로 ObjectProvider
이다. 참고로 과거에는 ObjectFactory
가 있었는데 여기에 편의 기능을 추가해서 ObjectProvider
가 만들어졌다.
prototypeBeanProvider.getObject()
을 통해서 항상 새로운 프로토 타입 빈이 생성되는 것을 확인할 수 있다. ObjectProvider
의 getObject()
를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다. ( DL )ObjectProvider
는 지금 딱 필요한 DL정도의 기능만 제공한다.특징
JSR-330 Provider
마지막 방법은 javax.inject.Provider
라는 JSR-330 자바 표준을 사용하는 방법이다.
이 방법을 사용하려면 javax.inject:javax.inject:1
라이브러리를 gradle에 추가해야한다.
public interface Provider<T> {/**
* Provides a fully-constructed and injected instance of {@code T}.
* @return instance of {@code T}.
*
* @throws RuntimeException if the injector encounters an error while
* providing an instance. For example, if an injectable member on
* {@code T} throws an exception, the injector may wrap the exception
* and throw it to the caller of {@code get()}. Callers should not try
* to handle such exceptions as the behavior may vary across injector
* implementations and even different configurations of the same injector.
*/
T get(); }
provider.get()
을 통해서 항상 새로운 프로토타입 빈이 생성되는 것을 확인할 수 있다.provider
의 get()
을 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.( DL )Provider
는 지금 딱 필요한 DL정도의 기능만 제고한다.특징
get()
메서드 하나로 기능이 매우 단순하다.정리
ObjectProvider
,JSR330 Provider
등은 프로토타입 뿐만 아니라 DL이 필요한 경우는 언제든지 사용할 수 있다.| 참고 : 스프링이 제공하는 메서드에 @LOOKUP
애노테이션을 사용하는 방법도 있지만 , 이전 방법들로 충분하고 , 고려해야할 내용도 많아서 생략!
| 참고 : 실무에서 자바 표준인 JSR-330 Provider를 사용할 것인지, 아니면 스프링이 제공하는 ObjectProvider를 사용할 것인지 고민이 될 것이다. ObjectProvider는 DL을 위한 편의 기능을 많이 제공해주고 스프링 외에 별도의 의존관계 추가가 필요 없기 때문에 편리하다. 만약 ( 정말 그럴일은 거의 없겠지만 )코드를 스프링이 아닌 다른 컨테이너에서도 사용할 수 있어야 한다면 JSR-330 Provider를 사용해야한다.
스프링을 사용하다 보면 이 기능 뿐만 아니라 다른 기능들도 자바 표준과 스프링이 제공하는 기능이 겹칠때가 많이 있다. 대부분 스프링이 더 다양하고 편리한 기능을 제공해주기 때문에 , 특별히 다른 컨테이너를 사용할 일이 없다면, 스프링이 제공하는 기능을 사용하면 된다.