코드 그라데이션

스프링 빈 조회 (1) - 기본 / 동일한 타입이 둘 이상인 경우 본문

Spring/핵심 원리 구현

스프링 빈 조회 (1) - 기본 / 동일한 타입이 둘 이상인 경우

완벽한 장면 2024. 1. 22. 22:37

Case 1) 조회 - 기본

스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적인 조회 방법

  • `ac.getBean(빈이름, 타입)`
  • `ac.getBean(타입)`

조회 대상 스프링 빈이 없으면 예외 발생

=> `NoSuchBeanDefinitionException: No bean named 'xxxxx' available

 

 

ApplicationContextBasicFindTest

package inflearn.spring_core.beanfind;

import inflearn.spring_core.config.AppConfig;
import inflearn.spring_core.member.MemberService;
import inflearn.spring_core.member.MemberServiceImpl;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

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

class ApplicationContextBasicFindTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    /**
     * "memberService" 이름
     * MemberService.class 타입
     */
    @Test
    @DisplayName("빈 이름으로 조회")
    void findBeanByName() {
        MemberService memberService = ac.getBean("memberService", MemberService.class);

        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }


    @Test
    @DisplayName("이름 없이 타입만으로 조회")
    void findBeanByType() {
        MemberService memberService = ac.getBean(MemberService.class); // 타입만

        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName("구체 타입으로 조회")
    void findBeanByName2() {
        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);

        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName("빈 이름으로 조회X")
    void findBeanByNameX() {
//ac.getBean("xxxxx", MemberService.class);
        Assertions.assertThrows(NoSuchBeanDefinitionException.class,
                () -> ac.getBean("xxxxx", MemberService.class));
        // xxxxx 이런 이름의 빈이 지금 없다.
    }

}
System.out.println("memberService = " + memberService );
System.out.println("memberService.getClass() = " + memberService.getClass());

이렇게 찍어보면 정상적으로 출력됨(존재함)을 확인할 수 있으니 이 부분은 생략하고 작성.

 

구체 타입으로 조히하면 변경 시 유연성이 떨어진다.

 


스프링 빈 조회 - 동일한 타입이 둘 이상

  • 타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 오류가 발생한다. 이때는 빈 이름을 지정하자.
  • `ac.getBeansOfType()` 을 사용하면 해당 타입의 모든 빈을 조회할 수 있다.

 

ApplicationContextSameBeanFindTest

 

먼저

// 테스트 코드용 static 클래스 생성
@Configuration
static class SameBeanConfig {
    @Bean
    public MemberRepository memberRepository1() {
        return new MemoryMemberRepository();
    }
    @Bean
    public MemberRepository memberRepository2() {
        return new MemoryMemberRepository();
    }
}

 

첫 번째 테스트 메서드

    @Test
    @DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
    void findBeanByTypeDuplicate() {
        MemberRepository bean = ac.getBean(MemberRepository.class);
    }

이거 실행을 돌리면

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'inflearn.spring_core.member.MemberRepository' available: expected single matching bean but found 2: memberRepository1,memberRepository2

이런 에러 메시지가 나온다.

2개인데, 뭘 택해야 하는지를 모른다.

 

테스트 성공하도록 바꾸려면

    @Test
    @DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
    void findBeanByTypeDuplicate() {
//        MemberRepository bean = ac.getBean(MemberRepository.class);
        assertThrows(NoUniqueBeanDefinitionException.class,
                () -> ac.getBean(MemberRepository.class));
    }

 

 

다음 메서드

@Test
@DisplayName("타입으로 조회 시 같은 타입이 둘 이상 있으면, 빈 이름을 지정하면 된다")
void findBeanByName() {
    MemberRepository memberRepository = ac.getBean("memberRepository1", MemberRepository.class);

    assertThat(memberRepository).isInstanceOf(MemberRepository.class);

    // "memberRepository1" 라고 이름 적어뒀음.
}

이름 지정하면 문제 없이 찾을 수 있음.

 

다음 메서드

@Test
@DisplayName("특정 타입을 모두 조회하기")
void findAllBeanByType() {
    Map<String, MemberRepository> beansOfType = ac.getBeansOfType(MemberRepository.class);

    for (String key : beansOfType.keySet()) {
        System.out.println("key = " + key + " value = " + beansOfType.get(key));
    }

    System.out.println("beansOfType = " + beansOfType);
    assertThat(beansOfType.size()).isEqualTo(2);
}

이렇게 다 조회하면 Map으로 나온다고 한다.

 

실행 결과

 

728x90
Comments