[스프링 핵심 원리] 6. 컴포넌트 스캔

건우·2025년 9월 8일

Back-end / Java, Spring

목록 보기
6/14
post-thumbnail

컴포넌트 스캔과 @Autowired — 이제는 내가 안 만들고, 스프링이 만든다

지금까지는 이렇게 했다.

  • @Bean으로 직접 등록
  • AppConfig에서 객체 생성
  • 생성자 주입 연결

솔직히 말해서, 객체가 몇 개 안 될 때는 괜찮다.
근데 수십, 수백 개 되면?

설정 클래스가 지옥이 된다.

그래서 등장한 게 컴포넌트 스캔 + 자동 의존관계 주입이다.


1. 컴포넌트 스캔이 뭐냐면

기존 방식:

@Bean
public MemberService memberService() {
    return new MemberServiceImpl(memberRepository());
}

이제는 이런 설정을 안 써도 된다.

@Component
public class MemberServiceImpl implements MemberService {
}

그리고 설정 클래스에

@ComponentScan

만 붙이면 끝이다.

스프링이 알아서:

  • @Component 붙은 클래스 찾고
  • 스프링 빈으로 등록한다.

2. 근데 왜 @Configuration도 스캔되냐?

이 부분이 재밌다.

@Configuration 안에 들어가보면
실제로 @Component가 붙어있다.

즉, @Configuration도 결국 @Component의 일종이다.

그래서 컴포넌트 스캔을 켜면
이전 AppConfig 같은 설정 클래스도 같이 등록된다.

그래서 예제에서는 excludeFilters로 기존 설정 클래스를 제외했다.


3. 의존관계는 누가 넣어주냐? → @Autowired

이제 AppConfig가 없다.
그럼 의존관계는 어디서 연결하냐?

정답은 생성자에서 @Autowired.

@Component
public class OrderServiceImpl implements OrderService {

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository,
                            DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}

스프링이:

  • 타입 기준으로 빈을 찾고
  • 자동으로 생성자에 주입한다.

이건 내부적으로

getBean(MemberRepository.class

를 자동으로 해주는 거라고 보면 된다.


4. 스캔 시작 위치는 어디부터?

컴포넌트 스캔은 기본적으로
설정 클래스가 위치한 패키지부터 하위 패키지 전체를 스캔한다.

그래서 권장 패턴은:

  • 프로젝트 최상단 루트 패키지에 설정 클래스 배치

스프링 부트에서는 이게 자동이다.

@SpringBootApplication

이 안에 이미 @ComponentScan이 들어있다.
실무에서는 거의 설정 위치를 따로 지정 안 한다.


5. 기본 스캔 대상은 @Component만이 아니다

스프링은 이런 것들도 스캔한다.

  • @Controller
  • @Service
  • @Repository
  • @Configuration

이유는?
이 애노테이션들 안에 전부 @Component가 들어있기 때문이다.

근데 각 애노테이션의 차이점은?

단순히 스캔용이 아니다.

  • @Controller → MVC 컨트롤러로 인식
  • @Repository → 예외를 스프링 예외로 변환
  • @Configuration → CGLIB 처리 (싱글톤 보장)
  • @Service → 사실 특별한 기능은 없음 (의미적 구분)

즉, 스프링은 애노테이션을 “의미”로도 사용한다.


6. 필터는 거의 안 쓴다

includeFilters, excludeFilters로

  • 특정 애노테이션만 스캔
  • 특정 타입 제외

이런 것도 가능하다.

근데 솔직히 말하면
: 실무에서 거의 안 쓴다.

요즘은

  • 기본 스캔 유지
  • 패키지 구조를 잘 잡는 게 더 중요하다.

7. 중복 등록 문제

자동 vs 자동

같은 이름이면 바로 예외 발생

ConflictingBeanDefinitionException

이건 오히려 안전하다.

수동 vs 자동

예전 스프링
: 수동 빈이 자동 빈을 덮어씀

이게 진짜 무섭다.

  • 개발자가 의도한 건지
  • 실수인지
  • 설정 꼬인 건지

구분이 안 된다.

그래서 최근 스프링 부트는
수동 + 자동 충돌 시 기본적으로 오류 발생

이게 훨씬 낫다.


8. 내가 느낀 핵심

컴포넌트 스캔은 단순히 “자동 등록”이 아니라

객체 생성 책임을 설정 클래스(AppConfig)에서
“애노테이션 기반 구조”로 이동시킨 것

그리고 @Autowired는
“이제 내가 new 안 하고, 스프링이 연결해준다” 선언


9. 한 줄 정리

컴포넌트 스캔은
설정 코드를 줄이는 기능이 아니라, 구조를 애노테이션 중심으로 바꾸는 전환점이다.


출처
스프링 핵심 원리 - 기본편 (김영한, 인프런, 2020)

0개의 댓글