이번 포스팅은 Spring 4.3에서 추가된 인터페이스에 대해서 알아보자. 다 알아보기에는 필자도 어느 것이 추가 된지 정확하게 몰라서 다 알아보지는 못하고 제목에 써 있는 그대로
ObjectProvider
대해서 간략하게 살펴보자. 나중에 더 살펴봐야 겠다.
ObjectProvider
을 알아보기전에
ObjectFactory
을 잠깐 살펴보자.
ObjectFactory
은
org.springframework.beans.factory
패키지 안에 들어 있고 메서드(
getObject()
)가 한개 존재하며 이 메서드는 해당하는 인스턴스를 리턴하는 그런 메스드이다.
이 인터페이스는 인터페이스명 그대로 팩토리 빈을 생성 할 때 사용하는 인터페이스이다.
ObjectFactoryCreatingFactoryBean
클래스와 기타 다른 구현체를 사용해서 생성하면 된다.
하지만 지금은 필자가 말할려고 하는 것은 팩토리 빈을 생성하는 것은 아니고 이미 등록된 빈을 사용하려고 쓸 경우를 보려고 한다.
예를 들어 아래와 같은 샘플 코드가 있다고 가정하자.
@Configuration
public class ObjectProviderExample {
@Bean
public BeanClass beanClass() {
return new BeanClass("wonwoo");
}
private static class BeanClass {
private final String name;
public BeanClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("BeanClass{");
sb.append("name=").append(name).append(\\);
sb.append(});
return sb.toString();
}
}
}
단순한 스프링 코드이다. 그냥 클래스를 빈으로 등록하는 정도만 있다. 딱 보면 그냥 별거 없기에 위 소스의 설명은 생략하자. 그리고 나서 아래와 같은 코드가 있다고 하자.
@Configuration
publi class Provider {
public Provider(ObjectFactory<BeanClass> factory) {
BeanClass object = factory.getObject();
System.out.println(object);
}
}
위와 같이
ObjectFactory
를 사용해서 DI를 받으면 어떻게 될까? 보나마나 잘 될 것이다. getObject() 를 호출하면 아까 위에서 등록해둔
BeanClass
정보가 들어가 있다. 그럼 무엇을 위해 저
ObjectFactory
를 사용했나. 어떤 여러한 이유가 있겠지만 필자는 Lazy 로딩할 때 자주 쓸일 것으로 예상되고 있다. 실제로
getObject()
메서드를 호출하는 순간 해당 클래스가 빈으로 등록이 된다. (물론 getObject() 메서드를 사용하지 않더라도 Spring이 DI가 끝나면 등록은 한다.)
@Configuration
public class Provider {
public Provider(BeanClass beanClass) {
System.out.println(beanClass);
}
}
실제 위와 같이 코딩을 했다면 빈으로 등록이 된
beanClass
가 오겠지만
ObjectFactory
를 사용하면
getObject()
를 호출하면 그때 빈으로 등록이 된다.
@Bean
public BeanClass beanClass() {
return new BeanClass("wonwoo");
}
하지만 만약 아까 위에서 BeanClass를 등록한 위의 코드를 삭제하면 어떻게 될까? 물론 에러가 난다. 그러면 에러가 어디에서 날까? 위의 설명을 잘 읽었다면 바로 알 것이다.
BeanClass object = factory.getObject();
위 부분에서 에러가 발생한다. ObjectFactory
까지는 DI가 되었는데 BeanClass의 등록된 빈이 없으니 못찾아서 에러가 발생한다.
만약 저기에서 에러가 나지 않는다면 어떨까? 그럼 좀 더 확장성 있게 설정 할 수 있지 않을까?
그래서 ObjectFactory
보다 향상된 DI가 Spring 4.3에 추가 되었다. ObjectProvider<T>
인터페이스로 ObjectFactory
를 상속하고 있다.
일단 예제로 보자.
public Provider(ObjectProvider<BeanClass> provider) {
BeanClass ifAvailable = provider.getIfAvailable();
BeanClass ifUnique = provider.getIfUnique();
System.out.println(ifAvailable);
System.out.println(ifUnique);
}
아까와 동일한 생성자지만 ObjectFactory
에서 ObjectProvider
로 변경을 하자. getObject()
를 제외하고 3개의 메서드가 있는데 그중에서 2개의 메서드만 살펴보자.
둘다 동일하게 해당하는 빈이 없다면 null을 리턴하고 에러는 발생하지 않는다.
먼저 getIfAvailable()
이 메서드 경우에는 동일한 클래스의 빈이 2개 있다면 에러가 발생한다. 이 경우에는 @Primary
나 @Qualifier
사용해서 사용할 빈을 정해주면 된다.
getIfUnique()
메서드 경우에는 동일한 클래스의 빈이 2개 있다면 null을 리턴한다. 또 한 위의 메서드와 마찬가지로 @Primary
나 @Qualifier
사용할 경우에는 해당 빈이 등록 된다.
그러면 어디에다 위와 같은 클래스를 써먹을까? 대부분의 경우에는 필수가 아닌 옵션으로 설정을 할 떄 사용한다. Spring소스를 봐도 그러는 듯 하다. 설정 중에 있어도 되지만 굳이 없어도 되거나 좀 더 확장성있게 커스텀한 설정을 추가할 때 사용해도 될 것같다.
뭐 해당하는 예제는 각자가 한번 곰곰이 생각해서 만들어보자. 필자의 경우에는 Spring boot를 자주 사용하기 때문에 필자가 만든 자동 설정하는 부분 중에 옵션?? 같은 부분이 있었기에 사용했었다.
있어도 되지만 없어도 되는 설정이라..
아마 Spring boot 1.4를 사용한다면 Spring boot 소스를 참고하면 많은 곳에서 사용하고 있다.
뭐 딱히 그렇게 Spring를 사용하면서 많이 쓴다거나 개발할 때에는 중요한 부분은 아니지만 이런 것들도 존재하니 한번씩 살펴보는 것도 나쁘지 않다.
그리고 요즘 Spring 이 reactive 를 넘나 밀고 있다. 내년 Spring5에 reactive-web이 포함된다고 하니 천천히 살펴봐야겠다. 그리 급한건 아니니 천천히..