
Spring 컴포넌트 스캔 (Component Scan) 이란?
@ComponentScan과 @Autowired를 사용한 스프링 빈 자동 등록과 의존관계 자동 주입
Carefreelife98
3분 소요
컴포넌트 스캔과 의존 관계 자동 주입 이란?
- 기존 스프링 빈 등록 시에 @Bean 어노테이션이나, XML과 같은 설정파일의
<bean>태그를 사용하여 일일히 스프링 빈을 등록해주어야 했다 - 시스템이 거대해질수록 등록해야 할 스프링 빈이 그에 비례하여 많아지고, 누락 및 오타와 같은 문제가 발생하기 쉬워지며, 유지보수에 어려움이 생긴다
- 이에 설정 정보가 없더라도 자동으로 스프링 빈을 등록해주는 컴포넌트 스캔이라는 기능이 존재한다
- 의존관계 역시 자동으로 주입해주는
@Autowired어노테이션 또한 존재한다
@ComponentScan
1import org.springframework.context.annotation.ComponentScan;2import org.springframework.context.annotation.Configuration;3import org.springframework.context.annotation.FilterType;4
5@Configuration6@ComponentScan(7 excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)8)9public class AutoAppConfig {10
11}- 컴포넌트 스캔 사용 방법:
@ComponentScan어노테이션을 설정 정보 클래스 (@Configuration)에 적용- 컴포넌트 스캔을 적용한 설정정보 클래스 내에
@Bean을 통해 스프링 빈으로 등록한 클래스가 없는 것을 확인할 수 있다 - 컴포넌트 스캔은 말 그대로
@Component어노테이션이 적용된 클래스를 스캔하여 스프링 빈으로 등록한다 - 설정 정보 클래스가 여러 개 존재하는 경우와 같이 필터를 통해 컴포넌트 스캔에서 제외할 수도 있다
- 컴포넌트 스캔을 적용한 설정정보 클래스 내에
@Autowired
1@Configuration2public class AppConfig {3
4 ...5
6 @Bean7 public MemberService memberService() {8 return new MemberServiceImpl(memberRepository());9 }10
11 ...12
13}- ComponentScan을 사용하기 전에는 위처럼 설정 정보 클래스에서 의존 관계 주입을 해주었다
- 하지만 ComponentScan을 사용한 후, 설정 정보 클래스 내에서 빈을 직접 등록하지 않고,
@Component어노테이션이 적용된 클래스를 스프링 빈으로 자동 등록하기 때문에 의존 관계 주입 또한@Autowired메서드를 통해 해당 클래스 내에서 진행해 주어야 한다
1import org.springframework.beans.factory.annotation.Autowired;2import org.springframework.stereotype.Component;3
4@Component5public class MemberServiceImpl implements MemberService {6
7 private final MemberRepository memberRepository;8
9 @Autowired10 public MemberServiceImpl(MemberRepository memberRepository) {11 this.memberRepository = memberRepository;12 }13
14 @Override15 public void join(Member member) {16 memberRepository.save(member);17 }18
19 @Override20 public Member findMember(Long memberId) {21 return memberRepository.findById(memberId);22 }23}- 위와 같이 구현 클래스의 생성자에
@Autowired어노테이션을 적용하여 여러 의존관계 또한 한번에 주입받을 수 있다
컴포넌트 스캔과 자동 의존관계 주입 동작 과정
@ComponentScan
- 컴포넌트 스캔을 사용하는 경우 자동 등록되는 스프링 빈의 기본 이름(Default)은 해당 클래스명을 사용하되, 가장 앞글자를 소문자로 변경하여 등록되며, 직접 지정 또한 가능하다
- Default: MemberServiceImpl(클래스명) -> memberServiceImpl(스프링 빈 이름)
- Custom:
@Component("memberServiceCustom")과 같이 직접 빈 이름 부여 가능
@Autowired
- 생성자에
@Autowired를 적용하면, 스프링 컨테이너가 해당 스프링 빈을 찾아 자동 주입한다 - 기본 조회 전략은 "타입 조회" 를 통한 동일 타입 빈을 조회하여 주입한다
getBean(MemberRepository.class)와 동일한 기능을 수행
컴포넌트 스캔의 탐색 위치 및 기본 스캔 대상
탐색 대상 패키지의 루트 경로 지정
1@Configuration2@ComponentScan(3 basePackages = "hello.core.member",4 excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)5)6public class AutoAppConfig {7}@ComponentScan을 설정 파일에 적용 후,basePackages옵션을 설정해주지 않으면, 라이브러리를 포함한 해당 프로젝트 내 모든 자바 클래스를 스캔하게 되며, 이는 오랜 시간이 걸릴 수 있다- 따라서, 위와 같이
basePackages옵션을 적용하여 필요한 위치에서부터 그 하위를 탐색하도록 해주자- 이를 지정하지 않으면,
@ComponentScan이 적용된 설정 정보 클래스의 패키지가 시작 위치가 된다
- 이를 지정하지 않으면,
@ComponentScan TIP
@ComponentScan에 패키지 위치를 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두고 쓰면 좋다- 스프링 부트 사용 시에는 스프링 부트의 시작 설정 정보인
@SpringBootApplication을 프로젝트의 시작 루트 경로에 두고 사용하게 되며 해당 설정 내부에@ComponentScan이 존재한다
컴포넌트 스캔의 기본 대상
컴포넌트 스캔은 @Component 어노테이션이 적용된 클래스를 대상으로 하며, 아래와 같은 어노테이션 또한 내부적으로 @Component 어노테이션을 가지고 있으므로 컴포넌트 스캔의 대상이 되고, 그에 따른 부가 기능도 수행한다:
@Controller: 스프링 MVC 컨트롤러로서 인식@Service: 스프링 비즈니스 로직 구현@Repository: 스프링 데이터 접근 계층으로서 인식 및 데이터 계층의 예외를 스프링 예외로 변환@Configuration: 스프링 설정 정보로서 인식 및 스프링 빈의 싱글톤 유지를 위한 처리 수행
참고로, 자바 어노테이션에는 상속 관계가 존재하지 않는다. 특정 어노테이션 하위에 존재하는 어노테이션을 인식하는 것은 스프링이 지원하는 기능.