@Bean을 통해 설정 정보에 스프링 빈을 등록할 때 수십, 수백개가 되면 일일히 등록하는 것이 번거롭고, 누락이 생기기 쉽기 때문에 이러한 불편함을 줄이기 위해 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.
컴포넌트 스캔 시 @Component 어노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.
스프링 빈 등록 시 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다. (ex) OrderServiceImpl 클래스 -> orderServiceImpl)
스프링 빈의 이름을 직접 지정하고 싶으면 @Component("부여하고 싶은 이름") 으로 작성하면 된다.
스프링 컨테이너에 자동으로 빈을 등록하면 의존관계를 주입할 수 있는 방법이 없다. 전에는 하나하나 getBean을 통해 의존관계를 수동으로 설정했지만, 컴포넌트 스캔은 설정 정보 자체를 안쓰기 때문이다. 그래서 의존관계 자동 주입을 사용해서 주입을 해야한다.
생성자에 @Autowired를 지정하면 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다. 기본적으로 타입이 같은 빈을 찾아서 주입한다. 생성자에 파라미터가 많아도 다 찾아서 자동으로 주입한다.
@Configuration
@ComponentScan(
// 컴포넌트 스캔할 때 탐색할 패키지의 시작 위치를 지정하고, 이 패키지를 포함한 하위 패키지를 모두 탐색한다.
basePackages = "hello.core.member",
// 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다.
basePackageClasses = AutoAppConfig.class,
// 따로 패키지를 지정하지 않으면 디폴트로 @ComponentScan를 붙인 클래스의 패키지를 시작 위치로 이 패키지를 포함한 하위 패키지를 모두 탐색한다. (여기서는 hello.core가 시작 위치)
// 컴포넌트 스캔할 때 스프링 빈을 등록할 때 제외할 것 지정
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}
스프링부트는 @SpringBootApplication를 프로젝트 시작 루트 위치에 두어 설정 안에 @ComponentScan이 들어 있어 자동으로 스프링 빈이 등록되기 때문에 별도로 사용할 필요가 없다.
includeFilters, excludeFilters를 사용해서 어노테이션을 정의하고 추가해서 스프링 빈에 등록하거나 등록하지 않도록 설정할 수 있다.
public class ComponentFilterAppConfigTest {
@Test
void filterScan() {
ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class);
BeanA beanA = ac.getBean("beanA", BeanA.class);
Assertions.assertThat(beanA).isNotNull();
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 {
}
}
자동으로 빈을 등록했는데 수동으로도 빈이 등록되어 이름이 중복되는 경우에는 수동 빈 등록이 우선권을 갖는다. (수동 빈이 자동 빈을 오버라이딩한다.)
스프링부트에서는 수동 빈 등록과 자동 빈 등록 충돌 시 오류를 발생하도록 설정되어 있다.
만약.. 중복 등록을 허용하려면 application.properties에 spring.main.allow-bean-definition-overriding=true 설정하면 된다.
*참고 자료
스프링 핵심 원리 (김영한님)