컴포넌트 스캔이란?
@Component가 붙은 클래스를 자동으로 스프링 컨테이너에 스프링 빈으로 등록해준다.
이전엔 개발자가 스프링 컨테이너에 등록할 객체에 @Bean 붙여 직접 스프링 컨테이너에 스프링 빈을 등록했었다.
하지만 이제는 컴포넌트 스캔을 사용하면 개발자가 직접 하나하나 객체에 @Bean 을붙여 주는 일은 없을 것이다.
구현
우선 객체들의 의존관계에 대한 설정 클래스에 @ComponentScan 애너테이션을 붙인다.
@ComponentScan이 붙여진 설정 클래스는 이제 @Component가 붙은 객체들을 찾아 스프링 빈으로 등록해 줄것이다.
1
2
3
4
5
@Configuration
@ComponentScan
public class AutoAppConfig {
}
이제는 스프링 빈으로 등록할 객체들에게 @Component 애너테이션을 붙여주자.
MemberServiceImp.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class MemberServiceImp implements MemberService{
MemberRepository memberRepository;
public MemberServiceImp(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
OderServiceImp.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class OrderServiceImp implements OrderService{
MemberService memberService;
DiscountPolicy discountPolicy;
public OrderServiceImp(MemberService memberService, DiscountPolicy discountPolicy){
this.memberService = memberService;
this.discountPolicy = discountPolicy;
}
public Order createOrder(long memberId, String itemName, int itemPrice) {
Member findMember = memberService.findMember(memberId);
int discountPrice = discountPolicy.discount(findMember,itemPrice);
Order order = new Order(memberId, itemName, itemPrice, discountPrice);
return order;
}
}
MemoryMemberRepository.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class MemoryMemberRepository implements MemberRepository{
private static HashMap<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
이렇게 스프링 빈으로 등록할 객체들에게 @Component 애너테이션을 붙여주었다.
이때 스프링 빈의 기본이름은 클래스명으로 하되 앞글자만 소문자를 사용한다.
예) MemberServiceImp 객체의 스프링 빈의 이름은 “memberService” 가 된다.
만약 스프링 컨테이너에 등록할 객체가 늘어나도 단순히 @Component 애너테이션을 붙여주면 된다.
하지만 여기서 한번 생각해보자
지금 설정클래스를 보면 딸랑 애너테이션 2개만 붙어 있을것이다.
1
2
3
4
5
@Configuration
@ComponentScan
public class AutoAppConfig {
}
그렇다면 설정클래스에는 아무런 정보가 없는데 어떻게 의존관계를 주입해줄까?
@Autowired
스프링부트에서 제공해주는 의존 관계 자동 주입 애너테이션이다.
생성자에 @Autowired를 붙여주면 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입해준다.
이제 생성자에 @Autowired를 붙여주자.
MemberServiceImp.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component
public class MemberServiceImp implements MemberService{
MemberRepository memberRepository;
@Autowired
public MemberServiceImp(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Override
public void join(Member member) {
memberRepository.save(member);
}
@Override
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
OderServiceImp.class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class OrderServiceImp implements OrderService{
MemberService memberService;
DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImp(MemberService memberService, DiscountPolicy discountPolicy){
this.memberService = memberService;
this.discountPolicy = discountPolicy;
}
public Order createOrder(long memberId, String itemName, int itemPrice) {
Member findMember = memberService.findMember(memberId);
int discountPrice = discountPolicy.discount(findMember,itemPrice);
Order order = new Order(memberId, itemName, itemPrice, discountPrice);
return order;
}
}
생성자에 파라미터가 많아도 다 찾아서 주입해준다.
이제 컴포넌트가 제대로 작동하는지 테스트 해보자
1
2
3
4
5
6
7
@Test
void basicScan(){
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);
MemberService memberService = ac.getBean(MemberService.class);
Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
}
정상적으로 스프링 빈들이 등록된게 보인다.
컴포넌트 스캔 탐색 위치
기본적으로 @ComponentScan 애너테이션이 붙은 설정 정보 클래의 패키지 시작 위치부터 하위의 모든 클래스들을 스캔한다.
만약 탐색 위치를 변경하려면 basePackages 로 지정해줄 수 있다.
1
2
3
@ComponentScan(
basePackages = "위치지정"
}
보통은 패키지 위치를 변경하지 않고 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 방법을 사용한다.
그리고 스프링 부트를 생성하면 스프링 부트 대표 시작 정보인 @SpringBootApplication 를 보면 @ComponentScan이 붙어 있는것이 보인다.
컴포넌트 스캔 대상
그리고 컴포넌트 스캔은 @Component뿐만 아니라 다른 애너테이션들도 대상에 포함한다.
- @Component : 컴포넌트 스캔에 사용
- @Controller : 스프링 컨트롤러로 인식
- @Service : 스프링 비즈니 로직에서 사용
- @Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층예외를 스프링 예외로 변경
- @Configuration : 스프링 설정 정보 인식, 싱글톤 유지
이렇게 컴포넌트 스캔의 전반적인 흐름과 스캔 위치, 스캔 대상에 대해 공부해보았다.
다음에는 설명이 부족했던 의존 관계 자동 주입에 대해 공부를 해보겠다.
출처