컴포넌트 스캔
@Component를 가진 모든 대상을 가져와 Bean에 등록하기 위해 찾는 과정을 말한다. 즉, 빈 설정 파일과 @Bean을 통해 빈을 일일이 지정할 필요가 없다. 즉, 명시적인 등록과 달리, 자동으로 빈을 등록하는 방법이다.
1. xml 파일에 설정하기
<context:component-scan base-package="com.dx" />
2. Java 파일 안에서 설정하기 (*실무에서 많이 쓰는 방법)
@Configuration
@ComponentScan(basePackages = "com.dx")
public class AppConfig {
}
컴포넌트 스캔 대상
- @Component : 컴포넌트 스캔에서 사용한다.
- @Controller : Spring MVC Controller에서 사용한다.
- @Service : Spring Business 로직에서 사용한다.
- @Repository : Spring Data Access 계층에서 사용한다.
- @Configuration : Spring 설정 정보에서 사용한다.
- 아래 클래스 코드를 살펴보면 @Component를 포함하고 있다. (*이 상속 관계는 Spring 지원 기능, Java의 문법 X)
@Component
public @interface Controller {
}
@Component
public @interface Repository {
}
@Component
public @interface Configuration {
}
@ComponentScan
이 어노테이션이 있는 파일의 패키지 아래를 스캔한다.
탐색 위치
- basePackages를 사용하면 탐색할 패키지 시작 위치를 지정한다.
- 이 패키지를 포함하여 하위 패키지를 모두 탐색한다.
- basePackageClasses를 사용하면 지정한 클래스가 있는 패키지를 시작 패키지로 설정한다.
@ComponentScan (
basePackages = "com.dx.springEx"
// basePackages = {"com.dx.springEx01", "com.dx.springEx02"} 여러 개도 지정 가능하다.
)
권장 방법
구성 파일에 등록한다면 패키지 위치를 지정하지 않고, 설정 정보 클래스 위치를 Project 최상단에 둔다.
만약, Spring Boot를 사용한다면 @SpringBootApplication 안에 @ComponentScan이 포함되어 있으므로 자동으로 최상단으로 유지가 된다.
만약, 프로젝트 구조가 아래와 같다면,
1) com.dx
2) com.dx.service
3) com.dx.controller
4) com.dx.repository
~~~
1)번인 com.dx가 프로젝트 시작 루트이다. 이 위치에 AppConfig.java 로의 설정 정보 파일을 두고, @ComponentScan을 설정하면 된다. 결국 com.hello를 포함한 하위 패키지는 모두 컴포넌트 스캔의 대상이 된다.
@Autowired
이 어노테이션을 활용하여 생성자에 지정하면 스프링 컨테이너가 자동으로 조건에 맞는 Type을 찾아 의존성 주입을 자동으로 해준다.
필터
- includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.
- excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.
필터 등록 방법
1. 커스텀 어노테이션 정의
// 컴포넌트 스캔 대상에 추가
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyIncludeComponent {
}
// 컴포넌트 스캔 대상에서 제외
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyExcludeComponent {
}
2. 커스텀 어노테이션 대상 클래스에 적용
@MyIncludeComponent
public class ExampleA { // 컴포넌트 스캔 대상에서 추가
}
@MyExcludeComponent
public class ExampleB { // 컴포넌트 스캔 대상에서 제외
}
3. 컴포넌트 스캔 필터 설정
@Configuration
@ComponentScan(
excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class),
includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class))
static class ComponentFilterAppConfig {
}
4. 테스트 코드
public class ComponentFilterAppConfigTest {
@Test
public void filterScan() {
// 애플리케이션 컨텍스트 로드
ApplicationContext ac = new AnnotationConfigApplicationContext(
ComponentFilterAppConfig.class);
// ExampleA 타입의 빈을 가져온다.
ExampleA exampleA = ac.getBean(ExampleA.class);
// ExampleB 타입의 빈을 가져오려고 시도할 때 발생하는 예외를 캡처한다.
Throwable throwable = Assertions.catchThrowable(() -> ac.getBean(ExampleB.class));
// ExampleA 빈이 컨텍스트에 존재함을 확인한다.
Assertions.assertThat(exampleA).isNotNull();
// ExampleB 빈을 가져올 때 NoSuchBeanDefinitionException이 발생했음을 확인한다.
Assertions.assertThat(throwable).isInstanceOf(NoSuchBeanDefinitionException.class);
}
참고 자료
내용 참고 : 인프런 김영한 님의 강의 "스프링 핵심 원리 - 기본편"
https://blogshine.tistory.com/217
https://velog.io/@hyun-jii/%EC%8A%A4%ED%94%84%EB%A7%81-component-scan-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95
https://velog.io/@neity16/Spring-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-6-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%8A%A4%EC%BA%94Component-Scan-DI
'Spring' 카테고리의 다른 글
[Spring] 스프링 빈 스코프(Bean Scope) (0) | 2024.06.09 |
---|---|
[Spring] 빈 생명주기 콜백(Bean LifeCycle Callback) (0) | 2024.06.08 |
[Spring] 스프링 싱글톤 컨테이너(Singleton Container) (0) | 2024.06.06 |
[Spring] POJO(Plain Old Java Object)란? (1) | 2024.06.06 |
[Spring] 스프링의 삼각형(IoC/DI, AOP, PSA) (0) | 2024.06.05 |