컴포넌트 스캔이란 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능이다. 설정 클래스에서 빈으로 등록하지 않아도 원하는 클래스를 빈으로 등록할 수 있다.
@Component 애노테이션을 붙이면 해당 클래스를 스캔 대상으로 표시한다.
이 때 애노테이션에 속성값을 줄 수도 있다.
@Component("infoPrinter")
속성값을 주면 빈으로 등록할 때 사용할 이름을 지정할 수 있다. 속성값을 따로 설정하지 않으면 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 빈 이름으로 사용한다.
@Component 애노테이션을 붙인 클래스를 스캔해서 스프링 빈으로 등록하려면 설정 클래스에 @ComponentScan 애노테이션을 적용해야 한다.
@ComponentScan(basePackages = {"spring"})
여기서 basePackages 속성값은 스캔 대상 패키지 목록을 지정할 때 사용되는 속성값이다.
특정 대상을 스캔 대상에서 제외하고 싶다면 excludeFilters 속성을 사용할 수 있다.
excludFilters 속성은 다음과 같이 지정할 수 있다.
@ComponentScan(basePackages = {"spring"},
excludeFilters = @Filter(type = FilterType.REGEX,
pattern = "spring\\..*Dao"))
excludeFilters 안에서 @Filter 애노테이션의 type 속성값으로 정규표현식을 지정했다. 위의 코드를 적용하면 spring으로 시작하여 Dao로 끝나는 클래스는 컴포넌트 스캔 대상에서 제외된다.
이 외에도 특정 애노테이션을 붙인 타입을 컴포넌트 대상에서 제외할 수도 있다.
@ComponentScan(basePacakges = {"spring", "spring2"},
excludeFilters = @Filter(type = FilterType.ANNOTATION,
classes = {NoProduct.class, ManualBean.class}))
특정 타입이나 그 하위 타입을 제외하려면 ASSIGNABLE_TYPE을 FilterType으로 사용하면 된다.
@ComponentScan(basePacakges = {"spring"},
excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = MemberDao.class))
필터를 여러 개 지정하는 것도 가능하다.
@ComponentScan(basePacakges = {"spring"},
excludeFilters = {
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MemberDao.class),
@Filter(type = FilterType.REGEX, pattern = "spring\\..*Dao")
})
찾아보니 FilterType.CUSTOM을 통해 제외하고 싶은 패턴을 직접 지정할 수도 있었다.
https://www.baeldung.com/spring-componentscan-filter-type
@Componenet 애노테이션을 붙인 클래스만 컴포넌트 스캔 대상에 포함되는 것은 아니다. 다음 애노테이션을 붙인 클래스는 모두 컴포넌트 스캔 대상에 포함된다.
여기서 @Aspect를 제외한 나머지 애노테이션은 @Component 애노테이션에 몇 가지 기능이 추가된 특수 애노테이션이다.
컴포넌트 스캔을 통해 자동으로 빈을 등록할 때 충돌이 발생할 수 있다.
먼저 동일한 빈 이름을 사용하여 빈 이름 충돌이 발생하는 경우 BeanDefinitionStoreException 익셉션이 발생한다. 이를 해결하기 위해 속성값을 사용하여 명시적으로 빈 이름을 서로 다르게 설정해 줄 수 있다.
다음으로 수동 등록한 빈과 충돌이 발생할 수 있다. 스캔할 때 사용하는 빈 이름과 수동 등록한 빈 이름이 같은 경우 수동 등록한 빈이 우선된다.