[기본기] 6-1. 컨테이너, 빈

khyojun·2022년 9월 22일
0

본 게시글은 김영한님의 스프링 핵심 원리 기본편을 정리한 글입니다.


이전 시간에는 이제 본격적으로 스프링을 활용해보기위해서 우선적으로 코드로 스프링 컨테이너와 등록한 빈들을 가지고 간단한 코드를 만들어봤었는데 이번 시간부터 빈들이 어떻게 조회하고 확인할 수 있는지 알아보자.

컨테이너에 등록된 모든 빈 조회

📂 ApplicationContextTest

public class ApplicationContextTest {
    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 + " bean = " + bean);
        }
    }
 }

위 코드를 보면 이전에 말했었던 ApplicationContext 인터페이스의 구현체인 AnnotationConfigApplicationContext를 사용하여서 스프링 컨테이너를 생성한 후 String 배열을 하나 만들어서 컨테이너에 들어가는 빈의 이름들을 전부 다 불렀다. ac.getBeanDefinitionNames()를 통해서 그 이후 아래의 for문을 활용하여서 아까 불러왔던 빈들의 이름과 그리고 ac.getBean(빈 이름)빈 이름으로 객체를 조회한다.

자... 그러면 이제 테스트를 돌리면 다음과 같이 화면이 뜬다.

근데 아까 우리가 원래 불러오려고 하였던 빈들도 나오긴 하였지만 위에 org.springframework.~라고 적히면서 나오는 다른 빈들도 있다. 이것은 스프링이 내부적으로 사용하는 빈이 나오게 된다. 근데 우리가 확인하고 싶은건 뭐다?! 바로 우리가 직접 등록한 빈들만 확인을 하고 싶은데;;; 그렇게 하는 방법이 있다고 한다.

애플리케이션 빈 출력하기

 @Test
    @DisplayName("애플리케이션 빈 출력하기")
    void findAppBean(){
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){
                Object bean = ac.getBean(beanDefinitionName);
                System.out.println("name = " + beanDefinitionName + " bean = " + bean);
            }
        }
 }

위 코드랑 별로 그렇게 다른거 같지는 않지만 if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION)이라는 코드가 추가되었다. 여기서 보면 beanDefinition을 통하여서 .getRole()를 통하여서 스프링 내부적으로 사용하는 빈을 제외시킬 수 있다. 값은 다음과 같다.

BeanDefinition.ROLEAPPLICATION : 직접 등록한 애플리케이션 빈
BeanDefinition.ROLE
INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈

다음과 같은 것을 조건문과 함께 조합하면 위에 나온 결과처럼 스프링 내부에서 사용하는 빈만 출력을 할 것인지 아니면 직접 등록한 빈만 출력을 시킬 것인지 조절을 할 수 있다.

기본적으로 하는 스프링 빈 조회

기본적으로 위에 코드들에서도 계속 적었는데

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

위와 같은 두 가지 방법으로 조회를 할 수 있는데 어떻게 조회하는지 코드를 통하여서 확인해보자.

📂 ApplicationContextBasicFindTest

 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 이름으로 조회")
    void beannameShow(){
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        OrderService orderService = ac.getBean("orderService", OrderService.class);

        System.out.println("memberService = " + memberService);
        System.out.println("orderService = " + orderService);

        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
        Assertions.assertThat(orderService).isInstanceOf(OrderService.class);

    }

    @Test
    @DisplayName("빈 타입으로만 조회")
    void beanTypeShow(){
        MemberService memberService = ac.getBean( MemberService.class);
        OrderService orderService = ac.getBean(OrderService.class);

        System.out.println("memberService = " + memberService);
        System.out.println("orderService = " + orderService);

        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
        Assertions.assertThat(orderService).isInstanceOf(OrderService.class);

    }

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

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

        Assertions.assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }
    
     @Test
    @DisplayName("빈 이름으로 조회 x")
    void beanNameShow_X(){
       // MemberService memberService = ac.getBean("asdf",MemberServiceImpl.class);

        org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> ac.getBean("asdf",MemberServiceImpl.class));

    }

위 코드에 4가지 경우를 다 넣었는데

  1. 빈 이름으로 조회
  2. 빈 타입으로만 조회
  3. 빈 구체 타입으로 조회
  4. 빈 이름으로 제대로 조회하지 않았을 때

각각 경우를 보면 ac.getBean("빈 이름", 반환 타입) 이런 식으로 대부분 넣는데 3번째의 경우 우리가 등록한 빈은 memberService이지만 그것의 하위 타입은 자동적으로 연계되서 조회가 된다는 것을 알 수 있었고 그리고 4번째의 경우에는 주석 처리되어있는 코드를 작성하였을때 asdf라는 이름의 빈은 없으므로 NoSuchBeanDefinitionException이라는 오류를 출력하게 된다. 그리하여 assertThrows를 활용하여 테스트를 통과할 수 있도록 코드를 작성하였다.

출처

  1. 김영한님의 스프링 핵심 원리 기본편(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)
profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글