도대체 빈이 아닌 객체가 왜 빈을 받고 싶은 일들이 생기는 것이고 어떻게 해결해야 할까?
스프링 IoC 컨테이너가 관리하는 객체를 빈(bean)이라고 부르고 스프링은 빈에만 의존성을 주입해 줍니다. 물론 아주 고오오오오급진 방법을 쓰면 빈이 아닌 객체에도 빈을 주입하는 방법이 있긴하지만 10년 전에 그 기술을 레퍼런스에서 보고 공부 삼아 해본 적 이후로 한번도 실무에서 그 방법이 쓰인걸 본적이 없습니다. 그러니까 그 고오오오급진 방법은 패스. (궁금하신 분들은 스프링, @Configurable
이라는 키워드로 검색해보세요.)
그럼 다시 본론으로 돌아가서 어떤 경우에 빈이 아닌 객체에 빈을 주입하고 싶어질까? 다양한 경우가 있겠지만, 웹 애플리케이션을 개발하다보면 종종 스프링 데이터 JPA를 통해 만든 Repository를 Validator 또는 Interceptor에서 쓰고 싶은 경우가 있다.
그런데 Validator나 Interceptor를 사용하는 예제를 보면 대부분 new를 사용해서 다음과 같이 등록하는 모습을 볼 수 있다.
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new NotificationInterceptor());
}
@InitBinder("studyForm")
public void studyFormInitBinder(WebDataBinder webDataBinder) {
webDataBinder.addValidators(new StudyValidator);
}
그럼 이제 어떻게 해야 할까?
NotificationInterceptor
나 StudyValidator
는 아직 빈이 아니라서, 다른 빈을 주입 받지 못하는데 어떻게 하지?
빈으로 만들거나, 의존성을 직접 주입하면 된다.
- 빈으로 만들기
@Component
@RequiredArgsConstructor
public class NotificationInterceptor implements HandlerInterceptor {
private final NotificationRepository notificationRepository;
}
이런식으로 NotificationInterceptor
에 @Component
애노테이션을 추가해서 빈으로 등록하면, 이제부터는 다른 빈을 주입받을 수 있으니 생성자를 통해 스프링이 자동으로 NotificationRepository
타입의 의존성을 주입해준다.
빈으로 등록했으니 이제부터는 쓸때로 new로 직접 생성하는게 아니라 NotificationInterceptor
를 주입 받아서 쓰면 된다. 이런식으로.
private final NotificationInterceptor notificationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(notificationInterceptor);
}
2. 직접 주입하기
굳이 해당 객체를 빈으로 만들고 싶지 않다면 스프링이 해주는 의존성 주입 말고 직접 의존성을 주입하는 방법도 있다. 대신 NotificationIntercptor
에 의존성을 주입 받을 수 있는 장치를 마련해야 하는 것은 이전 방법과 동일하다. 생성자 또는 Setter가 있어야한다는 말이다. 생성자가 너무 많아서 일일히 다 하나씩 추가해주는게 힘들다면 세터를 통한 주입을 고민해 보는것도 좋겠다. 아무튼! 이전 코드와의 차이라면 @Component
를 빼서 빈이 되지 않게끔 하는것 정도.
쓸때는 이제 직접 의존성을 주입해야 하니까 NotificationRepository
를 받아서 NotificationInterceptor
를 만들 때 생성자가 세터를 통해 의존성을 주입해주면 된다.
private final NotificationRepository notificationRepository;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new NotificationInterceptor(notificationRepository));
}
개인적으로는 전자의 방법 즉 빈으로 등록하는 방법을 선호한다. 굳이 싱글톤 객체로 쓰는데 문제가 없는 객체라면 빈으로 등록을 하지 말아야 할 이유가 전혀 없기 때문이다. 또한 후자의 방법은 불필요하게 NotificationRepository
를 다른 코드에 노출 시킨다는 문제도 있다.
