목차
- 컴포넌트 스캔 - 컴포넌트 스캔과 의존관계 자동 주입 시작하기
- 컴포넌트 스캔 - 탐색 위치와 기본 스캔 대상
- 컴포넌트 스캔 - 필터
- 컴포넌트 스캔 - 중복 등록과 충돌
의존 관계 자동 주입
지금까지는 @Bean이나 <bean>을 이용해 설정 정보(appConfig)에 직접 등록할 스프링 빈을 작성했다.
빈의 수가 많아지면, 등록하기도 귀찮고, 많고, 누락문제가 발생한다.
그래서 스프링은 다음과 같은 기능을 제공한다.
- 컴포넌트 스캔 : 스프링 설정 정보 없이 자동으로 스프링 빈을 등록해주는 기능
- 자동 의존관계 주입(@Autowired) : 의존관계(DI)를 자동으로 주입
즉, 컴포넌트 스캔이란,
AppConfig에 @Bean으로 등록하지 않아도, 자동으로 스프링 빈으로 등록되게 해주는 방법이며,
자동 의존관계 주입이란,
@Bean 이 있는 method에서 매개변수를 이용해 의존관계를 표현했다면, 이제는 @Autowired를 이용하여, 의존성을 타내준다.
코드로 확인해보자.
먼저 컴포넌트 스캔을 이용해서 구현할 AppConfig가 필요하다.
다음과 같이 core의 하위에 이름을 AutoAppConfig로 만들어준다.
AutoAppConfig
package hello.core;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan( //@Component annotation이 붙은 클래스를 자동으로 스캔해서 스프링 빈으로 등록해줌,
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
//@Component 가 붙은 클래스 중 자동스캔에서 @Configuration이 붙은 것은 제외할 것(AppConfig->@Configuration(얘도 내부에 @Component가 있음) 때문에 작성된부분)
)
public class AutoAppConfig {
}
AppConfig와 마찬가지로 @Configuration이라고 설정정보를 담았다는 의미의 annotation을 포함한다.
중요한 점은 내부에 @Bean으로 등록되지 않았다는 점과
@ComponentScan annotation을 부착했다는 점이다.
이는 @Component가 부착된 모든 클래스를 스캔하여, 스프링 빈으로 등록하겠다는 의미이다.
(그 아래에 exclude라고 적힌 부분은 주석을 참고) AppConfig를 고려하지 않기 위함이며, 실제로는 붙이지않음
이제 기존 AppConfig에 존재하는 4가지의 클래스에 @Component라는 annotation을 추가해준다.
MemoryMemberRepository
RateDiscountPolicy
MemberServiceImpl
OrderServiceImpl
자세히 보면,
MemberServiceImpl과 OrderServiceImpl은 의존관계를 가진다.
이는 그들이 생성자를 보면, 매개변수에 의존이 있는 모습을 볼 수 있는데, 생성자에 @Autowired를 부착하면, 자동으로 의존관계가 성립된다.
<끝>
실제로, appConfig와 동일하게 돌아가는지 확인하기 위해 다음과 같이 테스트 코드를 작성해준다.
scan이라는 패키지 하위에 AutoAppConfigTest를 생성한다.
다음과 같이 AutoAppConfig로 스프링 컨테이너를 생성하여, 간단한 테스트 코드를 실행해보면, 똑같이 실행됨을 알 수 있다.
package hello.core.scan;
import hello.core.AutoAppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
public class AutoAppConfigTest {
@Test
void basicScan(){
//autoAppConfig 사용
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberService.class);
}
}
컴포넌트 스캔과 자동 의존관계 주입의 작동
1. @ComponentScan
@ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다.
이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.
2. @Autowired의존관계 자동 주입
생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.
이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.
getBean(MemberRepository.class) 와 동일하다고 이해하면 된다.
파라미터가 여러개로 의존관계가 여러개여도 잘 작동한다.(orderServiceImpl처럼 2개인경우도 잘 작동)
탐색 위치
모든 자바 클래스를 하나하나 컴포넌트 스캔하면 시간이 오래걸리므로, 스캔 위치를 지정할 수 있다.
@ComponentScan(
basePackages = "hello.core",
}
basePackages : 탐색할 패키지의 시작 위치를 지정한다. 이 패키지를 포함해서 하위 패키지를 모두 탐색한다.
여러개를 적는 것도 가능하다.
지정하지 않으면, @ComponentScan이 붙은 클래스의 패키지가 시작위치가 된다.
따라서, 패키지 위치를 따로 지정하지 않고, 설정 정보 클래스(AppConfig)의 위치를 프로젝트 최 상단에 두는 것을 권장한다.
이런ㄹ 경우 com.hello를 포함한 하위가 모두 컴포넌트 스캔의 대상이 된다.
프로젝트의 메인 설정 정보는 프로젝트를 대표하기 때문에 시작 루트 위치에 두는 것이 좋다.
* 참고 : 스프링 부트의 대표 시작 정보인 @SpringBootApplicaiton를 프로젝트 시작 루트 위치에 두는 것이 관례(이 설정안에도 @ComponentScan 이 들어있음)
컴포넌트 스캔 기본 대상
컴포넌트 스캔은 @Component 뿐만 아니라 다음과 내용도 추가로 대상에 포함한다.
- @Component : 컴포넌트 스캔에서 사용
- @Controlller : 스프링 MVC 컨트롤러에서 사용
- @Service : 스프링 비즈니스 로직에서 사용
- @Repository : 스프링 데이터 접근 계층에서 사용
- @Configuration : 스프링 설정 정보에서 사용
이들은 모두 소스 코드를 열어보면 @Component를 포함한다.
(annotation에는 상속관계는 없다! annotation이 특정 annotation을 가지고 있는 것은 자바가 지원하는 기능이 아니며, 스프링에서 지원하는 기능이다.)
또한, 컴포넌트 스캔의 용도 뿐 아니라 부가기능을 수행한다.
- @Controller : 스프링 MVC 컨트롤러로 인식
- @Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층의 예외를 스프링 예외로 변환해준다.
- @Configuration : 앞서 보았듯이 스프링 설정 정보로 인식하고, 스프링 빈이 싱글톤을 유지하도록 추가있겠구나 라고 비즈니스 계층을 인식하는데 도움이 된다.처리를 한다.
- @Service : 사실 @Service 는 특별한 처리를 하지 않는다. 대신 개발자들이 핵심 비즈니스 로직이 여기에 있겠군 하며, 비즈니스 계층을 개발자가 인식하는데 도움을 준다.
(나중에 나올 것 그냥 대충)
또한, useDefaultfilters옵션은 기본적으로 on상태인데, 옵션을 끄면 기본 스캔 대상에서 제외 시킬 수도 있다.
'Backend > Spring' 카테고리의 다른 글
[Spring] 의존관계 자동 주입 1) 의존 주입 방법 (0) | 2021.10.06 |
---|---|
[Spring] 컴포넌트 스캔 2) 기타 사항 (0) | 2021.09.30 |
[Spring] 싱글톤 컨테이너 3) @Configuration (0) | 2021.09.30 |
[Spring] 싱글톤 컨테이너 2) 싱글톤 방식의 주의점 (0) | 2021.09.30 |
[Spring] 싱글톤 컨테이너 1) 싱글톤 컨테이너의 필요성 (0) | 2021.09.30 |