컴포넌트스캔 (@ComponentScan) 이란?

구현 클래스에 @Component를 붙여 스프링 빈에 등록하는 방법이다.

기존에 ApplicationContext 구현 클래스에서는 @Bean 에너테이션을 붙인 메서드만 스프링 빈으로 등록이 되었다.

모든 스프링 빈을 구현 클래스에서 나열하기 때문에 실수로 인해 누락이 많고, 반복 작업으로 인해 비효율적이였다.

// ComponentScan을 사용하지 않은 기존 방법
@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        System.out.println("call AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }
}

이를 해결하기 위해 나온 것이 컴포넌트스캔이며, @Component 를 포함한 구현 클래스가 모두 스프링 빈으로 등록이 된다.

기존에 사용했던 것과 같이 의존 관계를 주입할 수 있는 방법이 없기 때문에 생성자 위에 @Autowired를 붙여 의존 관계를 자동으로 주입한다. 

// ComponentScan을 사용한 방법
@Configuration
@ComponentScan
public class AutoAppConfig {
}

 

// ComponentScan 방식을 사용한 스프링 빈 등록
@Component
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }

    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

 

컴포넌트스캔의 동작 순서

  1. @Component 가 붙은 모든 클래스를 스프링 빈으로 등록 : 빈 이름 기본 전략은 클래스명을 사용하되 맨 앞글자만 소문자로 변경
  2. @Autowired 의존 관계 자동 주입 : @Autowired가 지정된 의존 관계를 스프링 빈에서 찾아서 주입 (기본 조회 전략은 타입임 )

컴포넌트스캔의 탐색 위치

basePackage를 지정하여 해당 패키지를 포함한 하위 패키지에서 @Component를 찾아서 스프링 빈에 등록하고, 지정하지 않으면 @ComponentScan이 붙은 클래스의 패키지가 시작 위치가 된다.

// ComponentScan 탐색 경로 사용 예시
@Configuration
@ComponentScan (
        basePackages = "hello.core"
        baseClasses = "Member"
)

패키지 위치를 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이 일반적이다.

스프링 부트를 쓰면 @SpringBootApplication을 프로젝트 시작 루트 위치에 놓는 것이 관례이며, 해당 에너테이션 안에 @ComponentScan이 포함되어 있다.

 

 

컴포넌트 스캔 대상

  • @Component : 컴포넌트 사용
  • @Controller : 스프링 MVC 컨트롤러에서 사용
  • @Service : 스프링 비지니스 로직에서 사용
  • @Repository : 스프링 데이터 접근 계층에서 사용
  • @ Configuration : 스프링 설정 정보

컴포넌트 스캔의 옵션

  • ANNOTATION: 기본값, 에너테이션을 인색해서 동작
  • ASSIGNABLE_TYPE : 지정한 타입과 자식 타입을 인식해서 동작
  • ASPECTJ : AspectJ 패턴 사용
  • REGEX : 정규표현식 사용
  • CUSTOM : TypeFilter 라는 인터페이스를 구현해서 처리
// ComponentScan 옵션 예시
@ComponentScan (
        excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)

 

컴포넌트 등록을 통한 빈 등록의 경우 서로 충돌이 발생할 수 있다. 빈 등록은 자동과 수동으로 수행하며, 이렇게 등록된 빈 간의 충돌이 발생하는 것을 의미한다. 충돌 상황은 자동  vs 자동 / 자동 vs 수동으로 나눌 수 있다.

 

  1. 자동 빈 등록 vs 자동 빈 등록
    • ConflictingBeanDefinitionException 예외 발생
    • 예외를 통해 불필요한 빈 등록을 제거 
  2. 자동 빈 등록 vs 수동 빈 등록
    • ApplicationContext 객체를 생성해서 테스트 시 overriding 한다는 메시지가 뜸
    • 스프링 부트로 실행하면 오류 메시지가 발생하며, overriding을 허용하고 싶다면 application.properties 에 설정하여 사용 가능

+ Recent posts