이번 방탈출 사용자 예약에서 아래와 같은 예제 코드가 있었는데, 무지성으로 복붙하고 나서 보니 @Bean에 대해 궁금함이 생겼다.
이 기회에 @Bean, @Component의 차이가 무엇인지에 대해 정리하고 어떤 경우에 사용하면 좋을지에 대해 이야기 해보고자 한다.
Spring Bean이란
스프링 부트에서 Bean은 Spring Container가 관리하는 객체들을 말한다.
따라서 내가 사용하고자 하는 객체를 Spring DI를 통해 사용하기 위해서는 객체를 Bean으로 등록하는 과정이 필요하다.
Spring Boot에서의 Bean 등록 방법
spring boot에서는 Bean을 등록할 수 있는 방법을 두가지를 제공한다.
spring은 xml 등의 방식도 제공하는 것 같으나 아직은 패스한다.
1. @Component
먼저 코드를 살펴보면 클래스 레벨에 붙일 수 있고,
@Component 어노테이션을 붙이게 되면 싱글톤으로 생성된 해당 객체를 Spring Container가 관리하게 된다.
예시로 Human이라는 인터페이스가 있고 그 구현체인 Moly가 있다고 하자.
Moly라는 클래스에 @Component가 붙여져 있기 때문에, 이제부터 스프링 Container는 Moly의 인스턴스 하나를 빈으로 관리하게 된다.
따라서 HumanController에서 Human에 대해 DI를 받고자 할 때,
스프링은 Human의 구현체이며 관리하고 있는 Bean인 Moly를 주입하게 된다.
따라서 /main으로 요청을 보냈을 때,
실행 콘솔에 "Hi, I'm Moly!"가 성공적으로 실행되는 것을 알 수 있다.
2. @Bean
@Bean은 @Component와 달리 메서드 또는 어노테이션 레벨에서 사용할 수 있다.
또한 보통 @Configuration가 붙은 클래스 레벨에서 선언을 하는데,
그 이유는 @Configuration가 작동하는 시점에 @Bean 어노테이션이 붙은 메서드들을 인식하여 빈으로 등록하기 때문이다.
때문에 @Configuration가 아닌 파일에 @Bean을 붙여도 스프링은 해당 메서드를 빈으로 인식하지 못한다.
위 예시 코드에서 Moly 클래스에 @Component 대신 @Bean을 사용하여 변경해보자.
@Bean의 인식이 필요하기 때문에 @Configuration을 달아줄 파일이 추가로 필요하다.
그 후 클래스 내에서 @Bean을 선언하게 되면 해당 메서드의 리턴 타입인 객체가 빈으로 등록된다.
마찬가지로 /main으로 요청을 보냈을 때,
실행 콘솔에 "Hi, I'm Moly!"가 성공적으로 실행되는 것을 알 수 있다.
그래서 언제 사용하면 좋을까?
@Component를 사용하면 좋은 경우
예제에서 확인할 수 있듯이, @Bean을 사용하게 되면 @Configuration 파일이 추가로 필요하다.
때문에 보통 직접 구현한 객체 또는 @Component를 붙일 수 있는 객체에는 최대한 이 방식으로 등록을 하는 것이 좋다고 생각한다.
@Bean을 사용하면 좋은 경우
반면 여러 구현체가 있는 경우에는 구현체들의 빈 등록을 직접 한 곳에 관리할 수 있기 때문에 오히려 @Configuration 파일을 통해 관리하는 것이 수월할 수도 있다.
또한 외부 라이브러리 즉, 내가 접근해서 @Component를 붙여줄 수 없는 파일들은 @Bean을 통해 빈을 등록해 사용하는 것이 더 수월하다.
Spring Bean으로 등록하지 않고 사용할 때마다 생성하면 안돼?
따라서 이와 같은 내용들을 학습하고 나의 코드를 다시보니, 오히려 @Component로 선언했던 AuthenticationPrincipalArgumentResolver와 AuthorizationInterceptor를 일회성으로 사용할 것 같은데, 굳이 빈 등록을 해주어 싱글톤으로 관리를 해야한다거나 해야할까? 라는 생각이 들었다.
오히려 객체를 한번 생성하는 것이 더 낫지 않을까? 라는 생각이였다.
Not Spring Bean이 나은 경우(POJO를 사용하는 경우)
스프링 코드 중에 찾아보면 Bean으로 관리하기보다는 직접 인스턴트를 생성하는 코드가 은근 많은 것을 알 수 있다.
항상 빈으로 등록하여 관리하게 되면 컨테이너가 관리해야 할 빈들이 너무 늘어나는 문제가 있을 수 있다.(뭐 당장 사용에는 큰 영향이 없겠지만 프로젝트 규모가 엄청 큰 경우, 이런 빈 관리도 생각해볼 수 있을 듯)
때문에 재사용이 있지 않거나 빈으로 관리해야 할 필요가 없다는 것이 확실해진다면, 새 인스턴스를 생성하는 것이 나을 수도 있다.
뭐든, 정답은 때에 따라 적절하게 사용하는 것이지만 요런 점들을 좀 더 고민해보기를 바라며, 글을 마무리 하겠다.
+) 빈 등록과 일관성
추가로, 이번 메타인지 스터디를 하면서 위 내용에 대해 다른 크루와 이야기를 나누었다.
그 크루 역시 @Component를 남용하게 되면 컨테이너가 관리해야 할 빈들이 너무 늘어나기 때문에 무조건 @Component를 사용하여 빈으로 등록되게 하는 것을 지양하라는 것 대한 논의였다.
하지만, 크루의 리뷰어가 스프링 프레임워크의 최대 장점이 컨테이너가 빈 객체를 관리해주는 것이며, 너무 관리 대상인 빈이 많은 경우는 고려하지 않아도 된다는 것이었다.
반대로 빈 등록을 해주는 것도 일관성이 필요한데, 다른 개발자가 내 코드를 유지보수 해야하는 상황에서 특정 클래스는 빈 등록이 되어있고 어떤 클래스는 또 되어있지 않다면, 이를 구분하기에는 굉장히 까다롭다는 것을 알아야한다고 했다.
빈 등록을 "일관성"이라는 측면에서 생각해보지 못하여 매우 흥미로웠지만 100프로 공감할 수는 없는 것 같다. 과연 다른 개발자가 대부분의 객체가 빈으로 등록되어 있음을 기대할까? 이 문제 또한 잘 모르겠다.
역시 상황에 따라 사용하되, 요런 고민 포인트들이 있을 수 있다는 것도 생각해보는 시간이었다 👍
'우아한테크코스 6기 > 2단계' 카테고리의 다른 글
gradle 살펴보기 (0) | 2024.06.23 |
---|---|
JPQL new 연산은 지양해야 할까? JPQL은 어떻게 동작할까? (0) | 2024.06.04 |
영속성 entity 와 domain entity 분리해보기 (0) | 2024.05.12 |
[방탈출 예약 관리] 템플릿 엔진과 @RestController (0) | 2024.05.12 |
[방탈출 예약 관리] @DiritesContext, 알고 쓰자 (0) | 2024.04.27 |