본문 바로가기
Web/spring study

[Spring] 스프링 빈 조회

by 장인이 2023. 1. 10.

0. 개요

 이번 게시물에서는 스프링 빈을 조회하는 법에 대해 작성할 것이다. 해당 게시물을 보기 전, 아래 링크의 글을 보고 오는 것을 추천한다.

(스프링 빈과 스프링 컨테이너)

 

1. 빈 등록

모든 설명에 나오는 예시 프로젝트의 설계 방식은 아래 링크를 참고
https://imgzon.tistory.com/114

 

 이번 게시물에서 조회 할 빈은 아래 게시물에서 자바 코드로 등록한 빈들이다.

(스프링 빈 자바 코드로 수동 등록)

 

 

2. 스프링 컨테이너에 등록된 모든 빈 조회

class ApplicationContextInfoTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
    
    @Test
    @DisplayName("모든 빈 출력하기")
    void findAllBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = ac.getBean(beanDefinitionName);
            System.out.println("name=" + beanDefinitionName + " object=" + bean);
        }
    }
    
    @Test
    @DisplayName("애플리케이션 빈 출력하기")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
            
            //Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
            //Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("name=" + beanDefinitionName + " object=" +bean);
            }
        }
    }
}

 

함수들을 확인해보자

 

- ac.getBeanDefinitionNames(): 스프링에 등록된 모든 빈 이름을 조회한다.

- ac.getBean("빈 이름"): 빈 이름으로 빈 인스턴스를 조회한다.

- .getRole() 함수로 스프링 빈을 구분할 수 있다.

  - ROLE_APPLICATION: 일반적으로 사용자가 정의

  - ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는

 

 

3. 기본적인 스프링 빈 조회

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);
        Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
        ac.getBean("xxxxx", MemberService.class));
    }
}

 스프링 컨테이너에서 빈을 찾기 위해서는 기본적으로 2가지 방법을 사용한다.

- ac.getBean("빈 이름", (타입))

- ac.getBean((타입))

 

 구체 타입으로도 조회를 할 수는 있지만, 권장되지 않는 방법이며 유연성이 떨어진다.

 

 

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

class ApplicationContextSameBeanFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
    
    @Test
    @DisplayName("타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
    void findBeanByTypeDuplicate() {
        //DiscountPolicy 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);
    }
    
    @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);
    }
    
    @Configuration
    static class SameBeanConfig {
    
        @Bean
        public MemberRepository memberRepository1() {
            return new MemoryMemberRepository();
        }

        @Bean
        public MemberRepository memberRepository2() {
            return new MemoryMemberRepository();
        }
    }
}

동일한 타입의 빈이 둘 이상 있을때 ac.getBean((타입))으로 찾을 시, 오류가 발생한다. 따라서 해결법으로는

 

1) ac.getBean("빈 이름", (타입)) 으로 빈 이름을 통해 구분한다

2) return type이 Map<>인 ac.getBeansOfType((타입)) 함수를 통해 해당 타입의 모든 빈을 조회한다.

 

 


위 내용은 김영한 님의 인프런 강의 "스프링 핵심 원리 - 기본편"의 내용과 강의자료를 토대로 작성된 게시글입니다.

강의 링크:

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

댓글