본문 바로가기
Backend

[Spring] 컴포넌트 스캔(자동 빈 등록 과정)이란?

by persi0815 2024. 12. 5.
'초보 웹 개발자를 위한 스프링 5 프로그래밍 입문' 챕터 4를 읽고 정리한 내용입니다. 

 

컴포넌트 스캔이란? 

Spring에서는 객체를 스프링 컨테이너가 관리하는 빈(Bean) 으로 등록해야 한다. 이를 위해 개발자는 설정 클래스에서 @Bean을 사용해 직접 등록할 수도 있지만, 컴포넌트 스캔(Component Scan) 을 활용하면 더욱 자동화된 방식으로 빈을 등록할 수 있다.

 

컴포넌트 스캔은 스프링이 특정 패키지를 검색하여 @Component가 붙은 클래스를 자동으로 빈으로 등록하는 기능이다. 즉, 개발자가 일일이 설정 클래스를 만들지 않아도 스프링이 알아서 클래스를 검색하여 빈으로 등록해주는 자동 빈 등록 방식이다. 이를 통해 개발자는 개발자는 쉽게 빈을 등록할 수 있으며, 코드의 유지보수성과 가독성을 높일 수 있다.

 

Spring Boot 애플리케이션에서는 @SpringBootApplication이 위치한 패키지와 그 하위 패키지가 기본적으로 컴포넌트 스캔 대상이 된다. 이 패키지 내부에서 @Component, @Service, @Repository, @Controller 등과 같은 애노테이션이 붙은 클래스를 자동으로 스캔하고, 이를 빈으로 등록한다.

 

컴포넌트 스캔 대상 애노테이션

컴포넌트 스캔을 통해 등록되는 애노테이션은 다음과 같다.

@Component 기본적인 스프링 빈 등록 (모든 빈의 부모 애노테이션)
@Controller MVC 컨트롤러(웹 요청 처리)
@RestController RESTful API 컨트롤러 (@Controller + @ResponseBody)
@Service 서비스 로직을 수행하는 클래스
@Repository 데이터 액세스 계층(DAO) 클래스
@Aspect AOP(Aspect-Oriented Programming)에서 사용
@Configuration 스프링 설정 클래스(Bean을 등록하는 클래스)

 

위에서 언급한 @Controller, @Service, @Repository 등은 모두 @Component를 확장한 특수한 형태이다.
즉, 모든 빈은 결국 @Component를 기반으로 스캔되며, Spring이 특정 기능을 구분하기 위해 추가적인 애노테이션을 제공하는 것이다.

 

@ComponentScan을 활용한 컴포넌트 스캔 설정

컴포넌트 스캔을 활성화하려면 설정 클래스에 @ComponentScan을 적용해야 한다.
하지만 Spring Boot에서는 @SpringBootApplication이 @ComponentScan을 포함하고 있기 때문에, 별도로 설정하지 않아도 자동으로 동작한다.

@Configuration
@ComponentScan(basePackages = {"com.example"})  // 특정 패키지만 스캔
public class AppConfig {}

 

위 코드처럼 @ComponentScan을 사용하면 특정 패키지만 스캔할 수 있도록 범위를 제한할 수 있다. 

 

@Component와 빈 이름 지정 (@Component("beanName"))

컴포넌트 스캔을 통해 등록된 빈의 기본 이름은 클래스명의 첫 글자를 소문자로 변환한 형태이다.
그러나 @Component("customName")처럼 값을 지정하면, 해당 이름으로 빈을 등록할 수 있다.

@Component("listPrinter")  // 빈 이름을 "listPrinter"로 지정
public class ListPrinter {
    public void print() {
        System.out.println("Printing list...");
    }
}

 

위 클래스는 listPrinter라는 이름으로 빈이 등록되므로, @Autowired 시 해당 이름으로 주입 가능하다. 

 

특정 패키지 제외하고 스캔하기 (excludeFilters)

특정 클래스를 빈으로 등록하고 싶지 않은 경우, excludeFilters를 사용하여 제외할 수 있다.

@Configuration
@ComponentScan(
    basePackages = "com.example",
    excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {NoProduct.class, ManualBean.class})
)
public class AppConfig {}

 

위 설정을 사용하면, @Controller가 붙은 클래스를 제외하고 스캔함하는데, 특정 패키지에서 일부 컴포넌트를 제외하고 싶은 경우 유용하다. 

 

@ComponentScan 없이 @Bean으로 직접 빈 등록하는 경우

컴포넌트 스캔을 사용하면 설정 클래스에서 수동으로 @Bean을 등록하지 않아도 빈이 자동으로 등록된다.
하지만, 특정한 경우에는 직접 @Bean을 선언하여 빈을 수동으로 등록할 수도 있다.

@Configuration
public class AppConfig {
    @Bean
    public MyComponent myComponent() {
        return new MyComponent();
    }
}

 

위 방식은 컴포넌트 스캔을 사용하지 않고, @Bean을 이용해 명시적으로 빈을 등록하는 방식이다.
보통 외부 라이브러리를 빈으로 등록해야 할 경우직접 객체를 제어하고 싶을 때 사용한다.

 

수동 등록한 빈과 충돌한다면?

스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같은 경우, 수동 등록한 빈이 우선된다. 

 

Spring Boot에서 @ComponentScan이 자동으로 적용되는 이유

Spring Boot에서는 일반적으로 @SpringBootApplication이 있는 패키지와 그 하위 패키지를 자동으로 스캔한다.
이는 @SpringBootApplication 내부에 @ComponentScan이 포함되어 있기 때문이다.

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}