Home [spring] 컴포넌트 스캔
Post
Cancel

[spring] 컴포넌트 스캔






컴포넌트 스캔이란?


@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);
    }


Untitled



정상적으로 스프링 빈들이 등록된게 보인다.





컴포넌트 스캔 탐색 위치



기본적으로 @ComponentScan 애너테이션이 붙은 설정 정보 클래의 패키지 시작 위치부터 하위의 모든 클래스들을 스캔한다.

만약 탐색 위치를 변경하려면 basePackages 로 지정해줄 수 있다.



1
2
3
@ComponentScan(
  basePackages = "위치지정"
}



보통은 패키지 위치를 변경하지 않고 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 방법을 사용한다.

그리고 스프링 부트를 생성하면 스프링 부트 대표 시작 정보인 @SpringBootApplication 를 보면 @ComponentScan이 붙어 있는것이 보인다.


Untitled





컴포넌트 스캔 대상



그리고 컴포넌트 스캔은 @Component뿐만 아니라 다른 애너테이션들도 대상에 포함한다.


  • @Component : 컴포넌트 스캔에 사용
  • @Controller : 스프링 컨트롤러로 인식
  • @Service : 스프링 비즈니 로직에서 사용
  • @Repository : 스프링 데이터 접근 계층으로 인식하고, 데이터 계층예외를 스프링 예외로 변경
  • @Configuration : 스프링 설정 정보 인식, 싱글톤 유지




이렇게 컴포넌트 스캔의 전반적인 흐름과 스캔 위치, 스캔 대상에 대해 공부해보았다.

다음에는 설명이 부족했던 의존 관계 자동 주입에 대해 공부를 해보겠다.






출처

출처:https://www.inflearn.com/course/스프링-핵심-원리-기본편

This post is licensed under CC BY 4.0 by the author.

[spring] 스프링 컨테이너에 스프링 빈 등록하기

[spring] 의존 관계 자동 주입