[스프링 핵심원리] - 5.컴포넌트 스캔 (1)

Chooooo·2022년 11월 4일
0
post-thumbnail

이 글은 강의 : 김영한님의 - "스프링 핵심원리 - 기본편"을 듣고 정리한 내용입니다. 😁😁


이번 챕터부터 컴포넌트 스캔에 대하여 공부할 것이다.
이번에는 컴포넌트 스캔과 의존관계 자동 주입에 대해서 공부해보자.

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

지금까지는 자바 코드의 @Bean이나 XML의 을 통해서 설정 정보에 직접 스프링 빈을 등록했다.

예제에서는 등록해야할 스프링 빈이 몇 개가 안됐지만 규모가 커지면 반복과 누락의 문제가 있다... 그래서

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

- 의존관계도 자동으로 주입하는 @Autowired 라는 기능도 제공한다.

기존 AppConfig.java는 과거 코드, 테스트를 유지하기 위해 남겨두고 새로운 AutoAppConfig.java를 만들자.

AutoAppConfig.java - @ComponentScan

컴포넌트 스캔을 사용하려면 @ComponentScan을 설정 정보에 붙여준다.

  • 기존의 AppConfig와는 다르게 @Bean으로 등록한 클래스가 하나도 없다!
  package hello.core;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

// 설정 정보
@Configuration
// @Component가 붙은 클래스를 자동으로 스프링 빈으로 등록(@Configuration이 붙은 클래스는 제외)
@ComponentScan(
       excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
}

(참고) 컴포넌트 스캔을 사용하면 @Configuration이 붙은 설정 정보자동으로 스프링 빈으로 등록된다.
이전에 만들었던 AppConfig, TestConfig 등의 설정 정보를 스프링 빈으로 등록되면 안되기 때문에 excludeFilters 를 사용하여 컴포넌트 스캔 대상에서 제외했다. (보통 설정 정보를 컴포넌트 스캔 대상에서 제외하지는 않음)

@Configuration이 붙은 클래스를 컴포넌트 대상에서 제외했지만!! (@Configuration이 붙은)AutoConfig는 직접 등록했기 때문에 컴포넌트 스캔과 무관하게 스프링 빈으로 등록된다.
(new Anno---로 등록했잖아!)

@Component, @Autowired 추가하기

각 클래스가 컴포넌트 스캔의 대상으로서 자동으로 스프링 빈 등록되도록 @Component 어노테이션을 붙인다.

즉! MemoryMemberRepository @Component 추가, RateDiscountPolicy @Component 추가
MemoryMemberRepository, RateDiscountPolicy가 자동으로 스프링 빈으로 등록된다.

@Component
public class MemoryMemberRepository implements MemberRepository{
	...
}

@Component
public class RateDiscountPolicy implements DiscountPolicy{
	...
}

MemberServiceImpl @Component, @Autowired 추가

@Component
public class MemberServiceImpl implements MemberService{
  // MemberServiceImpl 은 MemberRepository 인터페이스에만 의존
  private final MemberRepository memberRepository;

  // 의존관계 자동 주입(DI)
  @Autowired  // ac.getBean(MemberRepository.class)
  public MemberServiceImpl(MemberRepository memberRepository) {
      this.memberRepository = memberRepository;
  }
	...
}

MemberServiceImpl은 자동으로 스프링 빈으로 등록된다. MemberServiceImpl의 생성자의 파라미터로 MemberRepository 타입의 빈이 자동으로 주입된다.

OrderServiceImpl @Component, @Autowired 추가

@Component
public class OrderServiceImpl implements OrderService{
  // 인터페이스에만 의존하도록 변경(DIP 만족)
  private final MemberRepository memberRepository;
  private final DiscountPolicy discountPolicy;

  // 의존관계 자동 주입(DI)
  @Autowired  // ac.getBean(MemberRepository.class), ac.getBean(DiscountPolicy.class)
  public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
      this.memberRepository = memberRepository;
      this.discountPolicy = discountPolicy;
  }
  ...
}

OrderServiceImpl은 자동으로 스프링 빈으로 등록된다.
OrderServiceImpl의 생성자의 파라미터로 MemberRepository, DiscountPolicy 타입의 빈이 자동 주입된다.

AutoConfigTest.java

AnnotationConfigApplicationContext()의 설정정보를 AutoAppConfig 클래스로 넘겨준다. (나머지 부분은 동일)

package hello.core.scan;

import hello.core.AutoAppConfig;
import hello.core.member.MemberService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import static org.assertj.core.api.Assertions.*;

public class AutoAppConfigTest {

  @Test
  void basicScan() {
      // 설정 정보를 AutoAppConfig로 넘겨서 스프링 컨테이너 생성
      // AutoConfig는 스프링 빈으로 직접 등록됨
      ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class);

      // MemberService 조회
      MemberService memberService = ac.getBean(MemberService.class);
      // memberService 인스턴스가 MemberService 타입인지 검증
      assertThat(memberService).isInstanceOf(MemberService.class);
  }
}

결과보면 컴포넌트 스캔이 잘 동작해 스프링 빈이 자동으로 등록된 것을 확인할 수 있다.

컴포넌트 스캔과 자동 의존 관계 주입 동작 그림

1) @ComponentScan

@ComponentScan은 @Component가 붙은 모든 클래스를 자동으로 스프링 빈으로 등록한다.

  • @Configuration이 붙은 클래스도 스프링 빈으로 자동 등록된다. (@Configuration 내부에 @Component 가 있음)


<스프링 빈 이름>

1) 빈 이름 기본 지정: 클래스 명(맨 앞글자만 소문자로 변경)

e.g. MemberServiceImpl 클래스 -> memberServiceImpl

2) 빈 이름 직접 지정: @Component(스프링 빈 이름)

e.g. @Component("memberService2") -> memberService2

2) @Autowired 의존관계 자동 주입
생성자에 @Autowired를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.

  • 기본 조회 전략은 타입이 같은 빈을 찾아서 주입하는 것이다.

  • 생성자에 파라미터가 많아도 여러 의존관계를 한번에 주입받을 수 있다.


profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글