기존의 Spring MVC에서는 xml을 활용하여 Bean을 등록했다.
하지만 프로젝트 규모가 커짐에 따라 사용하는 요소들을 xml에 등록하는 것이 상당히 번거로워져 어노테이션(Annotation, @)을 활용한 Bean 등록 방법이 탄생하게 되었다.
🔹 Spring Bean
Spring에서는 Spring의 DI Container에 의해 관리되는 POJO(Plain Old Java Object)를 Bean이라고 부르며,
이러한 Bean들은 Spring을 구성하는 핵심 요소이다.
- POJO(Plain Old Java Object)로써 Spring 애플리케이션을 구성하는 핵심 객체이다.
- Spring IoC 컨테이너(또는 DI 컨테이너)에 의해 생성 및 관리된다.
- class, id, scope, constructor-arg 등을 주요 속성으로 지닌다.
[ Spring Bean 구성 요소 ]
- class : Bean으로 등록한 Java 클래스
- id : Bean의 고유 식별자
- scope : Bean을 생성하기 위한 방법 (singleton, prototype 등)
- constructor-arg : Bean 생성 시 생성자에게 전달할 파라미터
- property : Bean 생성 시 setter에 전달할 인수
Spring에서는 위와 같은 Bean의 구성 요소를 바탕으로 등록되어 있는 Bean을 싱글톤 객체로 생성하여 관리한다.
🔹 Spring Bean 등록 방법 (@Bean, @Configuration, @Component)
[ @Bean, @Configuration ]
다음과 같은 클래스가 있고, 이를 스프링 컨테이너에 등록해 보자.
public class BeanResource {
}
이 클래스를 Bean으로 등록하기 위해서는 명시적으로 설정 클래스에서 @Bean 어노테이션을 사용하여 수동으로 스프링 컨테이너에 Bean을 등록할 수 있다.
설정 클래스는 다음과 같이 @Configuration 어노테이션을 클래스에 붙여주면 된다.
@Configuration
public class ResourceConfig {
@Bean
public BeanResource beanResource() {
return new BeanResource();
}
}
@Bean을 사용해 수동으로 Bean을 등록해 줄 때는 메서드 이름이 Bean 이름으로 결정된다.
그러므로 중복된 Bean 이름이 존재하지 않도록 주의해야 한다.
[ @Configuration 안에서 @Bean이 Bean으로 등록되는 과정 ]
스프링 컨테이너는 @Configuration이 붙어있는 클래스를 자동으로 Bean으로 등록해두고, 해당 클래스를 파싱해서 @Bean이 있는 메서드를 찾아 Bean을 생성해 준다.
@Bean을 사용하는 클래스에는 반드시 @Configuration 어노테이션을 활용하여 해당 클래스에서 Bean을 등록하고자 함을 명시해 주어야 한다. Spring Bean으로 등록된 다른 클래스 안에서 @Bean으로 직접 등록해 주는 것도 동작을 한다. 하지만 @Configuration 안에서 @Bean을 사용해야 싱글톤을 보장받을 수 있으므로 @Bean 어노테이션은 반드시 @Configuration과 함께 사용해 주어야 한다.
이러한 @Bean 어노테이션을 사용하는 경우는 수동으로 직접 Bean을 등록해 줘야 하는 상황이며, 주로 다음과 같을 때 사용한다.
1. 개발자가 직접 제어가 불가능한 라이브러리를 활용할 때
2. 애플리케이션 전범위적으로 사용되는 클래스를 등록할 때
3. 다형성을 활용하여 여러 구현체를 등록해 주어야 할 때
예를 들어, 우리가 객체를 Json 메시지로 변경하기 위해 Gson과 같은 외부 라이브러리를 사용한다고 해보자.
그러면 해당 클래스를 싱글톤 빈으로 등록해 주어야 한 개의 객체만 생성하여 여러 클래스가 공유함으로써 메모리 상의 이점을 얻을 것이다. 그런데 해당 클래스는 우리가 만든 것이 아닌 가져다 쓰는 클래스일 뿐이므로 불가피하게 @Bean으로 등록해 줘야만 한다.
애플리케이션 전범위적으로 사용되는 클래스와 다형성을 활용하여 여러 구현체를 등록할 때 @Bean을 사용하면 좋은 이유는 한눈에 파악하여 유지 보수하기 좋기 때문이다.
예를 들어, 여러 구현체를 Bean으로 등록해 줄 때 어떠한 구현체들이 Bean으로 등록되는지 파악하려면 소스 코드를 찾아볼 필요 없이 해당 @Configuration 클래스만 보면 되기 때문이다.
하지만 이렇게 수동으로 직접 Bean을 등록하는 작업은 Bean으로 등록하는 클래스가 많아질수록 상당히 많은 시간이 들게 되고, 생산력 저하를 야기할 것이다. 그래서 스프링에서는 특정 어노테이션이 있는 클래스를 찾아서 Bean으로 등록해 주는 컴포넌트 스캔 기능을 제공한다.
[ @Component ]
스프링에서는 컴포넌트 스캔(Component Scan)을 사용해 @Component 어노테이션 있는 클래스들을 찾아 자동으로 Bean 등록을 해준다. 그래서 우리가 직접 개발한 클래스를 Bean으로 편리하게 등록하고자 하는 경우에는 @Component 어노테이션을 활용하면 된다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
@Component를 갖는 어노테이션으로 @Controller, @Service, @Repository 등이 있으며, 앞서 살펴봤던 @Configuration 역시 안에 @Component를 가지고 있다.
@Configuration 안에 있는 @Component에 의해 설정 클래스 역시 자동으로 Bean으로 등록되기 때문에 @Bean이 있는 메서드를 통해 Bean을 등록해 줄 수 있었던 것이다.
스프링은 기본적으로 컴포넌트 스캔을 이용한 자동 빈 등록 방식을 권장한다.
또한, 직접 개발한 클래스는 @Component를 통해 해당 클래스를 Bean으로 등록함을 노출하는 것이 좋다. 왜냐하면 해당 클래스에 있는 @Component만 보면 해당 Bean이 등록되도록 잘 설정되었는지 바로 파악할 수 있기 때문이다. @Bean을 이용하여 Bean으로 등록하는 작업도 번거로우며 Bean이 등록되었는지 파악하는 과정도 번거로워질 수 있다. 그러므로 위에서 말한 @Bean을 사용하여 수동으로 Bean을 등록해야 하는 경우를 제외한 대부분의 경우에는 자동 등록 방식을 사용하면 된다.
추가로 @Component를 이용한다면 Main 또는 App 클래스에서 @ComponentScan으로 컴포넌트를 찾는 탐색 범위를 지정해 주어야 한다. 하지만 Spring Boot를 사용 중이라면 @SpringBootConfiguration 하위에 기본적으로 포함되어 있어 별도의 설정이 필요 없다.
@Bean, @Configuration, @Component에 대해 요약하자면 아래와 같다.
🔸 @Bean, @Configuration
- 수동으로 스프링 컨테이너에 Bean을 등록하는 방법
- 개발자가 직접 제어가 불가능한 라이브러리를 Bean으로 등록할 때 불가피하게 사용된다.
- 유지보수성을 높이기 위해 애플리케이션 전범위적으로 사용되는 클래스나 다형성을 활용하여 여러 구현체를 Bean으로 등록할 때 사용한다.
- 한 개 이상의 @Bean을 제공하는 클래스의 경우 반드시 @Configuration을 명시해 주어야 싱글톤이 보장된다.
🔸 @Component
- 자동으로 스프링 컨테이너에 Bean을 등록하는 방법
- 스프링 컴포넌트 스캔 기능이 @Component 어노테이션이 있는 클래스를 자동으로 찾아 Bean으로 등록한다.
- 대부분의 경우 @Component를 이용한 자동 등록 방식을 사용하는 것을 권장한다.
- @Component 하위 어노테이션으로 @Controller, @Service, @Repository, @Configuration 등이 있다.
📃 reference
'Spring' 카테고리의 다른 글
[Spring] 의존성 주입(Dependency Injection, DI) (0) | 2025.01.01 |
---|---|
[Spring] @Configuration 안에서 @Bean을 사용해야 하는 이유 (0) | 2024.12.31 |
[Spring] @RequestParam, @RequestBody, @ModelAttribute (0) | 2024.12.09 |
[Spring] Dispatcher Servlet (0) | 2024.12.06 |
[Spring] @Controller와 @RestController 차이 (0) | 2024.11.30 |