[spring 핵심 기본] 컴포넌트 스캔

채원·2024년 7월 13일

스프링

목록 보기
14/18
post-thumbnail

출처) 인프런 스프링 핵심 원리 기본편 강의

컴포넌트 스캔

컴포넌트 스캔과 의존관계 자동 주입

@Bean을 통해 직접 스프링 빈을 등록하기에는, 누락의 위험이 있다.
→ 컴포넌트 스캔 사용

  • @ComponentScan : @Component가 붙은 컴포넌트를 다 끌고와서 등록
  • @Autowired : 의존 관계 자동으로 주입

@ComponentScan

  • AutoAppConfig.java (기존 AppConfig 살리기 위해서 따로 만듦)
  • 수동으로 빈을 등록했던 것과 다르게 AutoAppConfig 내부에 아무것도 등록하지 않음
  • 이전 실습에서 @configuration이 붙은 것들이 많으므로, 설정 정보를 제거해줌 (일반적으로 제거하진 않음)
package hello.core;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(
    excludeFilters =
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {}

이후 AppConfig에 등록했던 빈에 가서 (구현체들) @Component 붙이기
기존 AppConfig에서 했던, 의존 관계 주입을 위해 생성자에 @Autowired 붙이기
(클래스 안에서 의존관계 주입도 해결해야함)

...
@Component
public class MemberServiceImpl implements MemberService {
  private final MemberRepository memberRepository;

  @Autowired
  public MemberServiceImpl(MemberRepository memberRepository) {
    this.memberRepository = memberRepository;
  }

@ComponentScan을 통해서 컨테이너에 등록되는 형태

기본: 기존 클래스명이지만 맨 앞글자만 소문자로 등록됨
직접 지정: @Component("등록할 빈 이름")

@Autowired 의존 관계 자동 주입

의존 관계 주입은 생성자에 @Autowired를 지정하면, 스프링 컨테이너가 자동으로 주입함
스프링 컨테이너가 기본적으로 타입이 같은 빈을 찾아서 주입함

컴포넌트 스캔 탐색 위치, 대상

위치 지정

모든 컴포넌트를 다 스캔하는 경우 시간이 많이 걸린다.
basePackages: 탐색 시작 위치를 지정, 하위 패키지만 스캔
basePackageClasses: 지정한 클래스의 패키지부터 스캔

<예시>

... 
@ComponentScan(
	basePackages = {"hello.core", "hello.service"},
    basePackageClasses = AutoAppConfig.class,
    ...
    )

권장 방법
⭐️ 지정하지 않는 경우, @ComponentScan이 붙은 설정 정보가 패키지 시작 위치
패키지 위치 지정하지 않고, 설정 정보 클래스 (AppConfig)를 프로젝트 최상단에 두기

컴포넌트 스캔 대상

  • @Component: 컴포넌트 스캔에서 사용
  • @Controller: 스프링 MVC 컨트롤러에서 사용
  • @Service: 스프링 비즈니스 로직에서 사용
    - 특별한 처리는 없으나, 핵심 비즈니스 로직일 때
  • @Repository: 스프링 데이터 접근 계층에서 사용
  • @Configuration: 스프링 설정 정보에서 사용
    @Component가 아니여도, 내부에 @Component를 가지고 있어서 가능
    컴포넌트

필터

componentScan에서 include, exclude에 내가 만든 컴포넌트 애노테이션을 인자로 줘서 스캔 범위에 추가하거나, 제외하기

  • includeFilters
  • exlcudeFilters

애노테이션 만들기

package hello.core.scan.filter;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {}

테스트 코드
excludeFilters 옵션에 준 MyExcludeComponent는 등록되지 않음

public class ComponentFilterAppConfigTest {
	....
  @Configuration
  @ComponentScan(
      includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
      excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class))

⭐️ @Component면 충분, include 사용할 일 거의 없음, 스프링 부트 기본 설정에 최대한 맞춰 사용할 것

중복 등록과 충돌

컴포넌트 스캔에서 같은 빈 이름을 등록하는 경우 충돌 발생

2가지 상황

    1. 자동 빈 등록 vs 자동 빈 등록 ConflictingBeanDefinitionException 예외 발생
    1. 수동 빈 등록 vs 자동 빈 등록
      수동 빈 등록이 우선권을 가짐
      의도하지 않은 결과가 만들어질 수 있으므로, 애매한 상황은 만들지 않는게 좋다
      최근 스프링부트에서는 충돌이 나면 오류가 남

0개의 댓글