Spring

[Spring] Component Scan

gogi masidda 2023. 9. 2. 11:13

지금까지는 @Bean을 이용하여 설정 정보에 직접 등록할 스프링 빈을 나열했다. 하지만 이렇게 등록해야 할 스프링 빈이 수십, 수백개가 되면 일일이 등록하기도 귀찮고, 설정 정보도 커지고, 누락하는 문제가 발생할 수 있다.

그래서 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다. 이때, 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다. 만약 스프링 빈의 이름을 직접 지정하고 싶으면 @Component(”…”)를 사용하면 된다.

@Autowired를 사용하면 생성자에서 여러 의존관계도 한번에 주입받을 수 있다.

@Component
public class OrderServiceImpl implements OrderService{
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy; //DIP 준수를 위해
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy; // 어떤 구현체가 들어올지 모름. AppConfig(외부)에서 결정됨.
                                              // OrderServiceImpl은 실행에만 집중하면 됨.
    }
....

탐색 위치

  • basePackages = "hello.core.member", // 탐색 시작위치 지정
  • basePackageClasses = AutoAppConfig.class, // 지정한 클래스의 패키지를 탐색 시작 위치로 지정한다.
  • 탐색 시작 위치를 지정하지 않으면, @ComponentScan이 붙은 설정 정보 파일의 패키지 부터. → 설정 정보 파일을 프로젝트 최상단에 두기

컴포넌트 스캔 기본 대상

  • @Component
  • @Controller: 스프링 MVC 컨트롤러로 인식
  • @Service: 개발자들이 핵심 비즈니스 로직이 여기에 있겠구나라고 비즈니스 계층을 인식하는데 도움이 된다.
  • @Repository: 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
  • @Configuration: 스프링의 설정 정보로 인식

필터

  • 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();

//        BeanB beanB = ac.getBean("beanB", BeanB.class); // beanB는 제외되어서 조회되지 않음.
        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 {

    }
}

중복 등록과 충돌

  1. 자동 빈 등록 vs 자동 빈 등록
  2. 수동 빈 등록 vs 자동 빈 등록

자동 빈 등록 vs 자동 빈 등록

컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데, 그 이름이 같은 경우 스프링은 오류를 발생시킨다.

ConflictBeanDefinitionException 예외 발생.

수동 빈 등록 vs 자동 빈 등록

이 경우 수동 빈 등록이 우선권을 가진다. (수동 빈이 자동 빈을 오버라이딩 해버린다.)

하지만 현실은 개발자가 의도적으로 설정해서 이런 결과가 만들어지기 보다는 여러 설정들이 꼬여서 이런 결과가 만들어지는 경우가 대부분이다. 그러면 정말 잡기 어려운 버그가 만들어진다. 그래서 최근 스프링 부트에서는 수동 빈 등록과 자동 빈 등록이 충돌나면 오류가 발생하도록 기본 값을 바꾸었다.

728x90

'Spring' 카테고리의 다른 글

MVC 프레임워크 / Spring MVC-1  (1) 2023.12.21
[Spring] 빈 생명주기 콜백  (0) 2023.09.08
[Spring] Singleton Pattern  (0) 2023.08.31
[Spring] Spring Container  (0) 2023.08.29
[Spring] Spring Bean  (0) 2023.08.28