엔지니어로 가는 길

Spring 빈을 생성하는 또 다른 방법 FactoryBean 본문

프로그래밍/Spring

Spring 빈을 생성하는 또 다른 방법 FactoryBean

탐p슨 2021. 2. 9. 10:56
728x90

빈을 생성하는 방법: 리플렉션 + 디폴트 생성자

스프링의 빈은 기본적으로 클래스 이름과 프로퍼티로 정의된다. 스프링은 내부적으로 리플렉션 API를 이용해서 빈 정의에 나오는 클래스 이름을 가지고 디폴트 생성자를 통해 빈 오브젝트를 생성한다. 클래스의 이름만 알고 있어도 다음과 같이 리플렉션을 통해 오브젝트를 생성할 수 있다.

 

 

이외에도 빈을 만들 수 있는 여러 방법이 있는데 그중 하나인 FactoryBean에 대해 살펴보자.

 

빈을 생성하는 방법: FactoryBean

FactoryBean이란 스프링을 대신해서 오브젝트의 생성 로직을 담당하도록 만들어진 특별한 빈이다. FactoryBean을 통해 빈을 생성하는 방법을 살펴보기 전에 어떤 경우에 FactoryBean을 써야 하는지 생각해보자.

 

클래스 정보를 미리 알아낼 수 없는 경우

앞서 살펴본 디폴트 생성자를 이용하는 방법은 클래스 이름을 알고 있어야 한다. 즉, 클래스 이름을 알 수 없는 경우라면 디폴트 생성자를 이용하는 방법을 쓸 수 없다. 예를 들어 자바에서는 Proxy라는 클래스의 newProxyInstance()라는 메소드를 통해 다이나믹 프록시 오브젝트를 만들 수 있는데, 다이나믹 프록시 오브젝트의 클래스는 무엇인지 미리 알 수 없다. 클래스 자체도 내부적으로 다이나믹하게 새로 정의해서 사용하기 때문이다. 따라서 사전에 프록시 오브젝트의 클래스 정보를 미리 알아내 스프링 빈에 정의할 방법이 없다.

 

생성자가 private한 경우

또한 생성자가 private인 경우 디폴트 생성자를 이용하는 방법은 적절하지 않다. 생성자를 private으로 하고 별도의 팩토리 메소드를 만들어두었다는 것은 그만한 이유가 있기 때문이므로 이를 무시하고 강제로 오브젝트를 생성하면 위험하다. 물론 빈으로 등록할 수 없는 것은 아니다. 생성자가 private하다고 할지라도 리플렉션을 이용하여 접근 규약을 무시하고 강제로 접근하여 오브젝트를 만들 수는 있기 때문이다. 하지만 일반적으로 private 생성자를 가진 클래스를 빈으로 등록하는 일은 권장되지 않으며, 등록하더라도 빈 오브젝트가 바르게 동작하지 않을 가능성이 있다.

 

자, 이제 FactoryBean을 사용하는 방법을 살펴보자.

 

 

Message 클래스는 private 생성자를 가지며, newMessage()라는 팩토리 메소드를 가지고 있다. FactoryBean을 이용해 Message 오브젝트를 빈으로 등록하고 싶다면 다음과 같이 FactoryBean을 구현한 클래스를 만들어야 한다.

 

 

FactoryBean은 세 개의 메소드 getObject(), getObjectType(), isSingleton()를 갖는 인터페이스이다. 세 개의 메소드 모두 아주 직관적인 이름을 가지고 있다. 타입 매개변수로는 생성하고자 하는 빈의 클래스를 넣어주어야한다.

 

참고: (isSingleton() 메소드는 스프링 컨테이너에서 싱글톤인지를 나타내는 것이 아니라, FactoryBean에서 싱글톤으로 관리되는지를 나타낸다. Message의 newMessage() 메소드를 구현할 때 new 연산자를 이용하였으므로 isSingleton() 메소드는 false를 리턴하며, 이와 별개로 Message 오브젝트를 스프링 컨테이너에 싱글톤으로 관리할 수 있다.)

 

FactoryBean을 구현한 클래스를 빈으로 등록해주면 FactoryBean의 getObejct() 메소드에서 리턴하는 오브젝트를 빈으로 등록해준다. (FactoryBean 구현체도 빈으로 등록되고, FactoryBean의 getObject() 메소드에서 리턴하는 오브젝트도 빈으로 등록된다.) 이때 주의해야 할 점은 FactoryBean을 구현한 클래스의 오브젝트를 빈으로 등록할 때 이름을 생성하고자 하는 빈의 이름으로 지정해주어야 한다는 것이다. 만들고자 하는 빈의 이름을 FactoryBean 빈의 이름에서 따오기 때문이다. 위의 예에서는 Message 오브젝트를 빈으로 등록하고자 하므로 FactoryBean 구현체인 MessageFactoryBean을 빈으로 등록할 때 "message"라는 이름으로 등록하였다. 테스트해보자.

 

테스트

 

MessageFactoryBean을 "message"라는 이름으로 등록했지만 컨테이너에는 만들고자 했던 Message 타입의 오브젝트가 "message"라는 이름으로 담겨있음을 확인할 수 있다. FactoryBean 빈 자체를 가져오고 싶다면 빈 이름 앞에 '&'를 붙여주면 된다.

 

 

 

참고: 토비의 스프링 3.1 vol.1

728x90
Comments