스프링 핵심 원리 - 기본편 (4) 스프링 컨테이너와 스프링 빈

강아람·2022년 8월 22일
0
post-thumbnail

📖 스프링 컨테이너 생성

📚 ApplicationContext

스프링 컨테이너, 인터페이스이기 때문에 다형성 O

📒 AnnotationConfigApplicationContext

ApplicationContext의 구현체로 자주 사용되는 클래스
: Annotation을 기반으로 스프링 빈을 생성한다.

ApplicationContext h = new AnnotationConfigApplicationContext(AppConfig.class);

📚 스프링 컨테이너의 생성 과정

1) 스프링 컨테이너 생성

ApplicationContext h = new AnnotationConfigApplicationContext(AppConfig.class);

스프링 컨테이너를 생성하기 위해 구성 정보를 지정해주어야 하는데, 우리는 이 구성 정보를 AppConfig.class로 지정하여 생성했다.

2) 스프링 빈 등록

구성 정보로 지정한 AppConfig.class의 모든 메서드를 호출하여 이름은 메서드 이름, 값은 생성된 객체로 스프링 빈 저장소에 저장한다.

3) 스프링 빈 의존관계 설정 - 준비

4) 스프링 빈 의존관계 설정 - 완료

스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입(DI)한다.

실제로는 스프링 컨테이너는 스프링 빈 생성과 의존관계 주입을 동시에 처리한다.




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

📒 모든 빈 출력하기

@Test
@DisplayName("모든 빈 출력하기")
void findAllBean() {
    String[] beanDefinitionNames = ac.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        Object bean = ac.getBean(beanDefinitionName);
        System.out.println("name = " + beanDefinitionName + " Object = " + bean);
    }
}
  • ac.getBeanDefinitionNames(): 스프링에 등록된 모든 빈 이름 조회
  • ac.getBean() : 빈 이름으로 빈 객체(인스턴스) 조회

📘 애플리케이션 빈 출력하기

@Test
@DisplayName("애플리케이션 빈 출력하기")
void findApplicationBean() {
    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 + " Object = " + bean);
        }

    }
}
  • 스프링 빈의 role은 getRole()로 확인 가능
    • ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈(애플리케이션 개발을 위해 등록한 빈)
    • ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈




📖 스프링 빈 조회

◾ 빈 이름으로 조회

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

◾ 빈 타입으로 조회

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

◾ 구체 타입으로 조회 (구현체)

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

◾ 실패 case test

@Test
    @DisplayName("빈 이름으로 조회가 안됨")
    void findByNameX() {
    assertThrows(NoSuchBeanDefinitionException.class,
                () -> ac.getBean("xx", MemberService.class));
}



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

MemberRepository bean = ac.getBean(MemberRepository.class);

빈 타입으로 조회했을 때, 결과가 2개 이상일 경우 예외가 발생

@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);
}




📖 스프링 빈 조회 - 상속관계

◾ 부모 타입으로 조회했을 때 2개 이상의 빈 객체가 존재할 경우, 예외 발생

@Test
@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 중복 오류가 발생한다.")
void findBeanByParentTypeDuplicate() {
    assertThrows(NoUniqueBeanDefinitionException.class,
                () -> ac.getBean(DiscountPolicy.class));
}

◾ 부모 타입으로 조회했을 때 2개 이상의 빈 객체가 존재하면 이름으로 지정

@Test
@DisplayName("부모 타입으로 조회시, 자식이 둘 이상 있으면, 빈 이름으로 지정하면 된다.")
void findBeanByParentTypeBeanName() {
    DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy", DiscountPolicy.class);
    assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}

◾ 특정 하위 타입으로 조회

@Test
@DisplayName("특정 하위 타입으로 조회")
void findBeanBySubType() {
    RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
    assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}

◾ 부모 타입으로 모든 빈 객체 조회

@Test
@DisplayName("부모 타입으로 모두 조회하기")
void findAllBeanByParentType() {
    Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);
    assertThat(beansOfType.size()).isEqualTo(2);
    for (String key : beansOfType.keySet()) {
        System.out.println("key = " + key + " value = " + beansOfType.get(key));
    }
}

◾ Object 타입(조상)으로 모든 빈 객체 조회

@Test
@DisplayName(" 부모 타입으로 모두 조회하기 - Object")
void findAllBeanObjectType() {
    Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
    for (String key : beansOfType.keySet()) {
        System.out.println("key = " + key + " value = " + beansOfType.get(key));
    }
}



📖 BeanFactory와 ApplicationContext

📚 BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스
  • getBean() 제공

📚 ApplicationContext

  • BeanFactory 기능을 모두 제공 (상속)
  • 애플리케이션 개발에 필요한 부가기능도 함께 상속받아 제공

    예)

  • 메시지 소스를 활용한 국제화 기능
  • 환경변수
  • 애플리케이션 이벤트
  • 편리한 리소스 조회



📖 스프링 빈 설정 메타 정보 - BeanDefinition

📚 BeanDefinition

빈 설정 메타 정보

  • @Bean, <bean> 당 각각 하나씩 메타 정보가 생성된다.
  • 스프링 컨테이너(ApplicationContext)는 이 메타 정보를 기반으로 스프링 빈을 생성한다.
  • 스프링 컨테이너는 BeanDefinition만 알고 있으면 XML과 자바코드로 스프링 빈을 설정할 수 있다.

0개의 댓글