시작이 반

[Spring] 컴포넌트 스캔, @Autowired 본문

Programming/Spring

[Spring] 컴포넌트 스캔, @Autowired

G_Gi 2021. 5. 13. 01:32
SMALL

ComponentScan을 통해서 Component 어노테이션이 붙은 객체들을 스프링 컨테이너에 스프링 빈으로 등록하게 된다.

( ComponentScan은 스프링 부트를 시작시키는 메인 메소드의 @SpringBootApplication 어노테이션을 까보면 상단에 걸려있다. 즉, 메인 메소드의 패키지부터 스캔한다. )

( 어노테이션은 상속이 안됨 근데 어떻게 이식하냐? 자바 언어가 지원하는 것이아니라 스프링이 지원하는 것임 )

 

ComponentScan시 같은 이름이 여러개가 있을때 무엇을 스프링 컨테이너에 저장하는가?

- 자동 빈 등록 vs 자동 빈 등록 : 오류 -> 예외

- 수동 빈 등록 vs 자동 빈 등록 : 수동 빈 등록이 우선권을 가진다. 근데 최근 스프링 부트는 기본적으로 오류가 나도록 바뀜

으로 나뉘게 된다.

 

컴포넌트 스캔 대상

  • @Component
  • @Controller
  • @Service
  • @Repository
  • @Configuration

 

아래와 같이 해당 코드가 있다면

@Component
public class MemberServiceImpl implements MemberService{

    private final MemberRepository memberRepository;

    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

}
@Component
public class MemoryMemberRepository implements MemberRepository{

    private static Map<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);
    }
}

스프링 컨테이너의 스프링 빈 저장소에는 memberServiceImpl, memoryMemberRepositrory이렇게 2개가 등록이 될 것이다.

 

우리는 DIP방식에 따라 클래스는 인터페이스에만 의존해야한다.

그래서 memberServiceImpl에서 저장소의 인터페이스인 MemberRepository를 쓰고 생성자에서 구현체를 주입을 받는다.

 

Autowired는 의존 관계 자동 주입이다.

스프링 컨테이너에 등록된 같은 타입의 빈을 찾아서 주입한다.

 

앞서 스프링 컨테이너의 스프링 빈 저장소에는 memberServiceImpl, memoryMemberRepositrory 2개가 저장되어 있기 때문에 MemberRepository의 타입과 같은 빈인 memoryMemberRepositrory 찾아서 주입하게 된다.

 

그런데 같은 타입의 빈이 2개 이상 저장되어 있다면 어떻게 될까?

- 기본으로 NoUniqueBeanDefinitionException 라는 예외의 오류를 발생한다.

해결방법

- @Autowired 필드 명을보고 매칭

- @Quilfier -> @Quilfier 끼리 매칭 -> 빈 이름 매칭 : 추가 구분자

- @primary 사용 : 우선순위 결정

 

즉 Primary로 사용하되 서브 빈들은 Quilfier들을 사용하여 구분자를 지정한다.

 

LIST