오봉이와 함께하는 개발 블로그

Spring - 스프링 컨테이너와 빈 - 2(스프링 빈 조회 기본, 동일한 타입 둘 이상) 본문

BE/Spring

Spring - 스프링 컨테이너와 빈 - 2(스프링 빈 조회 기본, 동일한 타입 둘 이상)

오봉봉이 2022. 6. 6. 15:09
728x90

스프링 빈 조회 - 기본

  • 스프링 컨테이너에서 스프링 빈을 찾는 가장 기본적 조회 방법
    • ac.getBean(빈 이름, 타입)
    • ac.getBean(타입)
    • 조회 대상 스프링 빈이 없다면 예외 발생
      • NoSuchBeanDefinitionException: No bean named 'xxxxx' available
package hello.core.beanfind;

/*
...
*/

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

public class ApplicationContextBasicFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.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);
        // org.junit.jupiter.api.Assertions
        assertThrows(NoSuchBeanDefinitionException.class,
                () -> ac.getBean("xxxxx", MemberService.class));
    }
}

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

  • 타입으로 조회할 때 같은 타입의 스프링 빈이 둘 이상이면 발생.
    • 이때는 빈 이름을 지정해야 함
    • ac.getBeansOfType()을 사용하면 해당 타입의 모든 빈을 조회할 수 있음.
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class ApplicationContextSameBeanFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);

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

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

    @Test
    @DisplayName("특정 타입 모두 조회")
    void findAllBeanAllType() {
        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);
    }

    @Configuration // 여기 안에서만 사용하는 클래스(원본 Config를 수정하기 싫다)
    static class SameBeanConfig {
        @Bean
        public MemberRepository memberRepository1() {
            return new MemoryMemberRepository();
        }
        @Bean
        public MemberRepository memberRepository2() {
            return new MemoryMemberRepository();
        }
    }
}
출처 : 인프런 김영한 지식공유자님의 스프링 완전 정복 로드맵 강의
728x90
Comments