컴포넌트 스캔

박지원·2024년 1월 24일

Spring

목록 보기
2/9

컴포넌트 스캔과 의존관계 자동 주입 시작하기

지금까지는 빈 등록시 @bean 등을 통해 설정 정보에 직접 등록할 스프링 빈 나열 -> 비효율적

그래서! 스프링이 아래 두가지 기능 제공한다

  • 컴포넌트 스캔 : 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 기능
    • @Component 애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록
  • @Autowired : 의존관계도 자동으로 주입
    • @Component 를 쓰면 의존관계를 주입할 방법이 따로 없으므로 @Autowired 를 사용해서 의존성 주입을 해준다
    • 생성자에서 여러 의존관계도 한 번에 주입 받을 수 있다
@Configuration
@ComponentScan // @Component 가 어노테이션이 붙은 클래스를 찾아서 전부 스프링 빈으로 등록해준다
        (
                excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, classes = Configuration.class)
                //Configuration 을 빼는 것(AppConfig 가 자동으로 등록되면 안되기 떄문)
        )
public class AutoAppConfig {


}
  • 컴포넌트 스캔 사용하면 @Configuration을 부여놨던 설정 정보도 자동으로 등록되기 때문에, excludeFilters 를 이용해서 설정 정보는 스캔 대상에서 제외하였다
@ComponentScan
  • @Component가 붙은 모든 클래스를 스프링 빈으로 등록
  • 스프링 빈의 기본이름은 맨 앞글자만 소문자로 사용
@Autowired
  • @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입
  • 타입이 같은 빈을 찾아서 주입

탐색 위치와 기본 스캔 대상

탐색 대상

  • @Component
    • 컴포넌트 스캔에서 사용
  • @Controller
    • 스프링 MVC 컨트롤러에서 사용
    • 스프링 MVC 컨트롤러로 인식
  • @Service : 스프링 비즈니서 로직에서 사용
  • @Repository : 스프링 데이터 접근 계층에서 사용
    • 스프링 데이터 접근 계층으로 인식, 데이터 계층의 예외를 스프링 예외로 변환
  • @Configuration : 스프링 설정 정보에서 사용
    • 스프링 설정 정보로 인식
    • 스프링 빈이 싱글톤을 유지하도록 추가 처리

필터

  • includeFilters: 컴포넌트 스캔 대상 추가로 지정
  • excludeFilters: 컴포넌트 스캔에서 제외할 대상 지정
  
  // 대상에 추가할 애노테이션 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
    // 대상에 제외할 애노테이션 
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
  • BeanA, BeanB 클래스에 만든 애노테이션 적용
   @Test
    void filterScan(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);

        BeanA beanA = ac.getBean("beanA", BeanA.class);
        assertThat(beanA).isNotNull();

        Assertions.assertThrows(NoSuchBeanDefinitionException.class,
                ()->ac.getBean("beanB",BeanB.class));
    }

    @Configuration
    @ComponentScan(
            includeFilters = @Filter(type= FilterType.ANNOTATION, classes = MyIncludeComponent.class),
            excludeFilters = @Filter(type= FilterType.ANNOTATION, classes = MyExcludeComponent.class)
    )
    static class ComponentFilterAppConfig {
    }
  • includeFilters 로 MyIncludeComponent.class 등록 ->BeanA가 스프링 빈에 등록
  • excludeFilters 로 MyExcludeComponent.class ->BeanB는 스프링 빈에 등록 X

FilterType 옵션

  • ANNOTATION : 기본값 애노테이션을 인식해서 동작
  • ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작
  • ASPECTJ: AspectJ 패턴 사용
  • REGEX: 정규 표현식
  • CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리

중복 등록과 충돌

  • 같은 빈 이름이 등록될 경우
  1. 자동 빈 등록
    • ConflictingBeanDefinitionException` 예외 발생
  2. 수동 빈 등록 vs 자동 빈 등록
    • 수동 빈 등록이 우선권을 가진다 (오버라이딩)
  • 최근에 스프링 부트는 오류 발생하도록 바뀜

0개의 댓글