목표

1. 자바 설정 정보 없이 스프링 빈을 등록할 수 있는 '컴포넌트 스캔'을 배운다. 
2. 의존관계를 자동으로 주입하는 @Autowired 기능을 배운다. 

'컴포넌트 스캔' 목차

1. 컴포넌트 스캔과 의존관계 자동 주입 시작하기 (이번 포스팅)

2. 탐색 위치와 기본 스캔 대상 

3. 필터 

4. 중복 등록과 충돌 


1. 컴포넌트 스캔과 의존관계 자동 주입 시작하기

지금까지 애노테이션 기반 자바 설정 정보로 스프링 빈을 생성했다. 

실무에서는 스프링 빈이 수십 수백개가 필요한데, 관리할 것이 많으면 실수가 나오게 된다. 좀 더 편리한 방법이 있을까? 

스프링은 설정 정보 파일이 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔 기능을 제공한다. 

 

컴포넌트 스캔으로 자바 설정 정보를 대체해보자. 

AppConfig.class 는 그대로 두고, 새롭게 AutoAppConfig.class 를 만들자. 이제 컴포넌트 스캔으로 스프링 빈을 등록해보자. 

 

1) 자바 설정 정보 AutoAppConfig.class 만들고, @Configuration 과 @ComponentScan 를 붙인다. 

기존의 AppConfig.class와는 다르게 @Bean으로 등록한 클래스가 하나도 없다. 

@ComponentScan 애노테이션은 @Component가 붙은 클래스를 찾아서 전부 스프링 빈으로 등록한다. 

 

2) [ 참고 ]

excludeFilters = @ComponentScan.Filter() 는 기존 예제 코드들을 유지하기 위한 작업이다.

AppConfig.class와 여러 테스트 코드 에 @Configuration이 붙어있다. 이것들을 컴포넌트 스캔에서 제외하기 위한 코드를 입력하자. 

@Configuration 를 열어보면 @Component 애노테이션이 붙어있다. 그래서 @Configuration 도 컴포넌트 스캔의 대상이다. 

 

3) 각 클래스가 컴포넌트 스캔의 대상이 되도록 @Component를 붙여준다. 

MemoryMemberRepository, RateDiscountPolicy, MemberServiceImpl 에 붙인다. 

4) '컴포넌트 스캔'에서 의존관계 주입은 어떻게 할까?

이전 자바 설정 파일에서는  MemberServiceImpl 구현체에 MemberRepository 의존관계를 생성자를 통해 주입했다.

컴포넌트 스캔에서는 생성자에 @Autowired 를 붙여서 자동으로 의존관계를 주입한다. 

이전에 설정 파일 AppConfig.class 에서는 @Bean 으로 직접 설정 정보를 작성했고 의존관계도 직접 명시했다. 

이제는 설정 정보 파일 자체가 없기 때문에 의존관계 주입도 클래스 안에서 애노테이션으로 해결해야 한다. 

 

OrderServiceImple 클래스에도 @Component를 붙여서 스프링 빈으로 등록하고 @Autowired 로 의존관계를 주입하자. 

5) 컴포넌스 스캔으로 스프링 빈을 등록하고 Autowired로 의존관계가 주입됬는지 테스트 코드를 작성해보자.

* 로그에서 컴포넌트 스캔의 내용을 확인할 수 있다. 

org.springframework.context.annotation.ClassPathBeanDefinitionScanner 
- Identified candidate component class: 
file [/Users../corebasic/discount/RateDiscountPolicy.class]

org.springframework.context.annotation.ClassPathBeanDefinitionScanner 
- Identified candidate component class: 
file [/Users../corebasic/member/MemberServiceImpl.class]

* 로그에서 의존관계 주입을 확인할 수 있다. memoryMemberRepository 이름의 빈이 생성자를 통해 자동주입됨. 

Creating shared instance of singleton bean 'orderServiceImpl'
Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'memoryMemberRepository'
Autowiring by type from bean name 'orderServiceImpl' via constructor to bean named 'rateDiscountPolicy'

6) 컴포넌트 스캔과 자동 의존관계 주입이 어떻게 동작하는지 그림으로 알아보자. 

 

@ComponentScan @Component가 붙은 클래스를 찾아서 전부 스프링 빈으로 등록한다. 

스프링 빈의 기본 이름은 클래스명을 쓰는데 앞글자만 소문자로 바꿔서 쓴다. 직접 빈 이름을 지정할 수 도 있다. 

MemberServiceImpl - > memberServiceImpl

생성자에 @Autowired 를 붙이면, 스프링 컨테이너가 자동으로 해당 빈을 찾아서 주입한다. 

기본 조회 전략은 타입이 같은 빈을 찾는 것이다. 

아래 코드를 보면 MemberRepository 빈을 의존관계로 주입해야 하는 상황이다.

MemberRepository와 타입이 같은 것을 찾는다. 

memoryMemberRepository 가 MemberRepository의 구현체니까 타입이 맞다.

그래서 memoryMemberRepository를 꺼내서 주입한다. 

getBean(MemberRepository.class)와 동일하다고 이해하면 된다. 


2. 탐색 위치와 기본 스캔 대상

컴포넌트 스캔을 시작하는 위치와 대상에 대해 알아보자. 

 

1) 탐색할 패키지의 시작 위치 지정 : 탐색 위치를 지정 할 수 있다!

AutoAppConfig.class 파일을 열어보자. 어떤 패키지부터 탐색할 지 basePackages 를 지정할 수 있다. 

모든 자바 클래스를 다 컴포넌트 스캔하면 시간이 오래 걸리기 때문이다. 그래서 꼭 필요한 위치부터 탐색하도록 시작 위치를 지정할 수 있다. 

현재 프로젝트 네비게이션은 아래와 같이 여러개의 패키지로 구성되어 있다. 

member 패키지를 basePackages 로 지정하고 컴포넌트 스캔하면 어떻게 될까? 

basePackages = member 패키지를 포함해서 하위 패키지를 모두 탐색한다.

그래서 memberServiceImpl, memoryMemberRepository 만 스프링 빈으로 등록됬다.

orderServiceImpl같은 다른 패키지의 빈은 제외됬다. 

2) 탐색 위치를 지정하지 않으면 어떻게 될까? 

@ComponentScan 이 붙은 설정 정보 클래스의 위치 부터 하위 패키지를 모두 탐색한다. 

hello.corebasic 패키지 하위의 모든 자바 파일에 @Component가 붙었는지 검사한다. 

3) 권장하는 방법 : @ComponentScan 이 붙은 설정 정보 클래스의 위치를 최상단에 두자 ! 

최근 스프링부트도 이 방법을 기본으로 제공한다. 

 

예를 들어, 패키지가 아래와 같은 구조라면, hello.corebasic 여기가 프로젝트 시작 루트가 된다. (지금 AutoAppConfig.class위치)

프로젝트 시작 루트에 @ComponentScan 를 붙인 메인 설정 정보 클래스를 두고 basePackage 지정은 생략한다.

이렇게 하면 hello.corebasic  를 포함한 하위는 모두 컴포넌트 스캔의 대상이 된다. 

 

[ 참고 ] 스프링 부트를 사용하는 경우

스프링 부트의 대표 시작 정보인 @SpringBootApplication 를 이 프로젝트 시작 루트 위치에 두는 것이 관례이다. 

 

스프링 부트 프로젝트를 만들면 main() 메서드가 있는 프로젝트명으로 된 클래스가 자동 생성되어 있다. 

이 클래스에 이미 @SpringBootApplication 가 붙어있다. 

 @SpringBootApplication  애노테이션이 뭔지 싶어서 ctrl 을 누르고 들어가보면,  @ComponentScan 이 붙어있음을 확인할 수 있다.

그래서 스프링 부트를 실행하면 hello.corebasic 위치 부터 하위까지 다 스프링 빈이 등록된다.

스프링 부트를 쓰면 @ComponentScan 을 따로 달아줄 필요가 없다. 

 


4) 컴포넌트 스캔의 기본 대상

@ComponentScan뿐만 아니라 아래 내용도 컴포넌트 스캔 대상에 포함된다. 

  *  @Component 

  *  @Controller 

  *   @Service

  *   @Repository

  *   @Configuration

스프링 MVC를 다뤄봤다면 몇개는 익숙한 애노테이션일 것이다. 해당 클래스의 소스코드를 열어보면 @Component를 포함하고 있음을 확인할 수 있다. 

 

[ 참고 ] 애노테이션에는 상속관계 라는 것이 없다. 

애노테이션이 특정 애노테이션을 인식할 수 있는 것인 자바 언어가 지원하는게 아니라, 스프링이 지원하는 기능임을 인지하고 넘어가자. 

 

컴포넌트 스캔의 대상이 되면서도 아래의 애노테이션이 있으면 스프링은 부가 기능을 수행한다. 

예를 들어, @Controller 라면, MVC 컨트롤러로 인식한다. @Repository라면 데이터 계층의 예외를 스프링 예외로 변환해준다. 

 


다음 강의에서는 '컴포넌트 스캔의 필터와 빈 이름 중복'에 대해  배운다. 

공부 내용 출처 :  스프링 핵심 원리 기본편 

728x90

+ Recent posts