상속일 때 조회

부모 타입으로 조회하면 자식 타입도 함께 조회한다. 그래서 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면 모든 스프링 빈을 조회한다.

상속 관계가 위와 같다면 1번 타입으로 조회했을 때 모든 빈이 조회된다. 그 다음 번호들도 자기 자식만큼 나온다.

public class ApplicationContextInheritanceTest {

  AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);

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

  @Configuration
  static class TestConfig {

    @Bean
    public DiscountPolicy rateDiscountPolicy() {
      return new RateDiscountPolicy();
    }

    @Bean
    public DiscountPolicy fixDiscountPolicy() {
      return new FixDiscountPolicy();
    }
  }

}

자식이 둘 이상이라면 중복 오류가 발생한다.

참고로 TestConfig의 메서드들은 구체 타입이 아니라 인터페이스를 반환하도록 정의되어 있는데, 물론 구체 타입으로 반환해도 되지만 역할과 구현을 쪼개야 하기 때문에 이렇게 선언한 것이다.

빈 이름으로 지정해서 조회

public class ApplicationContextInheritanceTest {

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

}

특정 하위 타입으로 조회

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

}

이 방법은 구체 클래스로 조회하기 때문에 좋은 방법은 아니다.

부모 타입으로 모든 빈 조회

public class ApplicationContextInheritanceTest {

  @Test
  @DisplayName("부모 타입으로 모든 빈을 조회한다.")
  void findBeanByParentType() {
    Map<String, DiscountPolicy> beansOfType = ac.getBeansOfType(DiscountPolicy.class);

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

    assertThat(beansOfType.size()).isEqualTo(2);
  }

}

참고로 출력 로직은 공부를 위한 것이지 실제 테스트 코드에 넣으면 안된다. 테스트 통과 여부를 시스템이 결정하도록 해야하기 때문이다.

Object 타입으로 모든 빈 조회

public class ApplicationContextInheritanceTest {

  @Test
  @DisplayName("Object 타입으로 모든 빈을 조회한다.")
  void findBeanByObject() {
    Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);

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

}

스프링이 내부적으로 사용하는 빈까지 모두 출력되었다.


실제 프로젝트 코드에는 위와 같이 ApplicationContext를 직접 불러오는 일은 거의 없다. 하지만 부모가 여러 자식을 가질 때 어떻게 하는지 등을 알고 있어야 다음 개념을 이해할 수 있으므로 설명했다.

Last updated