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

  • 지금까지 스프링 빈을 등록할 때는 자바 코드의 @Bean 이나 XML의 <bean>등을 통해서 설정 정보에 직접 등록할 스프링 빈을 나열했다.
  • 스프링 빈이 수십 , 수백개가 되면 일일이 등록하기도 귀찮고, 설정 정보도 커지고 , 누락하는 문제도 발생한다.
  • 그래서 스프링은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 컴포넌트 스캔이라는 기능을 제공한다.
  • 의존관계도 자동으로 주입하는 @Autowired라는 기능도 제공한다.

AutoAppConfig.java

@Configuration
@ComponentScan( // @Component를 찾아 스프링 빈으로 등록해준다.
    // 기존 AppConfig.java는 등록이 되면 안되기 때문에
    // @Component 어노테이션을 찾을 때 제외할 어노테이션 (@Configuration)
    excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION 
            , classes = Configuration.class);
)
public class AutoAppConfig {

}
  • 컴포넌트 스캔을 사용하려면 먼저 @ComponentScan을 설정 정보에 붙여주면 된다.
  • 기존의 AppConfig와는 다르게 @Bean으로 등록한 클래스가 하나도 없다.
컴포넌트 스캔을 사용하면 @Configuration이 붙은 설정 정보도 자동으로 등록되기 때문에 AppConfig , TestConfig등 앞서 만들어 두었던 설정 정보도 함께 등록되고 , 실행 되어 버린다. 그래서 excludeFilters를 이용해서 설정 정보는 컴포넌트 스캔 대상에서 제외 했다.
보통 설정 정보를 컴포넌트 스캔 대상에서 제외하지는 않지만 , 기존 예제 코드를 최대한 남기고 유지하기 위해 작성했다.
(@Configuration 소스코드를 열어보면 @Component 애노테이션이 붙어있다.)

OrderServiceImpl

@Component
public class OrderServiceImpl implements OrderService{

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

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

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member , itemPrice);

        return new Order(memberId , itemName , itemPrice , discountPrice);
    }

    //테스트
    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}
@Component는 스프링 빈으로 바로 등록이 되어버려 의존관계를 @Autowired를 추가하여 의존관계를 주입한다.
  • 이전에 AppConfig에서는 @Bean으로 직접 설정 정보를 작성했고 , 의존관계도 직접 작성했다.
  • 이제는 이런 설정 정보 자체가 없기 때문에 , 의존관계 주입도 이 클래스 안에서 해결해야한다.

AutoAppConfigTest

public class AutoAppConfigTest {

    @Test
    void basicScan(){
        AnnotationConfigApplicationContext ac = 
        		new AnnotationConfigApplicationContext(AutoAppConfig.class);

        MemberService memberService = ac.getBean(MemberService.class);
        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
    }
}

 

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

 

  • @ComponentScan은 @Component가 붙은 모든 클래스를 스프링 빈으로 등록한다.
  • 이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.
    • 빈 이름 기본 전략 : MemberServiceImpl 클래스 -> memberServiceImpl
    • 빈 이름 직접 지정 : 만약 스프링 빈의 이름을 직접 지정하고 싶으면 @Component("memberService2")이름을 부여하면 된다

  • 생성자에 @Autowired를 지정하면 , 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.
  • 이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.
    • getBean(MemberRepository.class)와 동일하다고 이해하면 된다. 
    • 자세한 내용은 뒤에서 설명한다.

  • 생성자에 파라미터가 많아도 다 찾아서 자동으로 주입한다.

 

+  인터페이스의 구현체가 2개 이상일 때

예) OrderService에 DiscountPolicy(인터페이스)의 RateDiscountPolicy , FixDiscountPolicy(구현체) 둘 중 하나를 주입해줘야하는데 구현체 2개 다 @Component로 등록 하게 되면??

NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.discount.DiscountPolicy'
available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

 

 

 

 

 

 

스프링 핵심 원리 - 기본편 - 인프런

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다. 초급 프레임워크 및 라이브러리 웹 개발 서버 개발 Back-End Spring 객체지향 온

www.inflearn.com

 

'스프링 핵심 원리 > 컴포넌트 스캔' 카테고리의 다른 글

중복 등록과 충돌  (0) 2020.12.27
필터  (0) 2020.12.27
탐색 위치와 기본 스캔 대상  (0) 2020.12.27