article thumbnail image
Published 2021. 8. 30. 23:20

 

 

 

스프링 컨테이너 생성

 

 

스프링 컨테이너가 생성되는 과정

 

  • ApplicationContext를 스프링 컨테이너라고 한다.
  • ApplicationContext는 인터페이스이다.
  • 스프링 컨테이너는 (XML 또는) 애노테이션 기반의 자바 설정 클래스로 만들 수 있다.
  • 이전에 AppConfig를 사용했던 방식이 애노테이션 기반의 자바 설정 클래스로 스프링 컨테이너를 만든 것이다.

 

자바 설정 클래스를 기반으로 스프링 컨테이너를 만들어보자

 

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

 

AnnotationConfigApplicationContext 클래스는 ApplicationContext 인터페이스의 구현체이다.

 

정확히는 스프링 컨테이너를 부를 때 BeanFactory(거의 없음), ApplicationContext로 구분해서 이야기한다.

 

 

 

1. 스프링 컨테이너 생성

 

  • new AnnotationConfigApplicationContext(AppConfig.class)
  • 스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 한다.
  • 여기서는 AppConfig.class를 구성 정보로 지정했다.

 

 

2. 스프링 빈 등록

 

 

  • 빈 어노테이션이 붙은 것을 전부 호출해서 객체를 등록한다.
  • 빈 이름은 메서드 이름을 사용한다.(임의로 직접 부여할 수도 있다.)

 

주의: 빈 이름은 항상 다른 이름을 부여해야한다.

 

 

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

 

 

 

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

 

 

  • 설정 정보를 참고해서 의존관계 주입(DI)
  • 단순히 자바 코드를 호출하는 것과는 차이가 있다. (이후 설명)

 

참고:

스프링은 빈을 생성하고, 의존 관계를 주입하는 단계가 나누어져 있다.(스프링 라이프사이클 상)

위와 같이 자바 코드로 스프링 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한번에 처리된다.

여기서는 이해를 돕기 위해 개념적으로 나누어 설명

 

정리

스프링 컨테이너를 생성하고, 설정(구성) 정보를 참고해서 스프링 빈도 등록하고, 의존관계도 설정했다.

이제 스프링 컨테이너에서 데이터를 조회해보자.

 

 

 

 

 

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

 

 

public class ApplicationContextInfoTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("모든 빈 출력하기")
    void findAllBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) { // iter
            Object bean = ac.getBean(beanDefinitionName);
            System.out.println("Name = " + beanDefinitionName + ", object = " + bean);
        }
    }
}

 

결과

 

 

스프링 내부적으로 사용하는 Bean과 내가 등록한 Bean 전체가 출력된다.

 

 

 

내가 등록한 Bean만 출력하기

 

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

 

결과

 

 

  • ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회한다.
  • ac.getBean() : 빈 이름으로 빈 객체(인스턴스)를 조회한다.
  • 스프링이 내부에서 사용하는 빈은 getRole() 로 구분할 수 있다.

 

 

스프링 빈 조회 - 기본

 

  • ac.getBean(빈이름, 타입)
  • ac.getBean(타입)
  • 조회 대상 스프링 빈이 없으면 예외 발생 - NoSuchBeanDefinitionException

 

 

테스트 코드

 

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() {
        MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
        // 구현체로 적어도 되긴 함 
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }
}

 

실패하는 테스트도 반드시 해보기

 

@Test
    @DisplayName("빈 이름으로 조회 X")
    void findBeanByNameX() {
        MemberService xxxxx = ac.getBean("xxxxx", MemberService.class);
    }

@Test
    @DisplayName("빈 이름으로 조회 X")
    void findBeanByNameX() {
        // 아래 예외가 터져야 테스트 성공
        assertThrows(NoSuchBeanDefinitionException.class, () -> ac.getBean("xxxxx", MemberService.class));
    }

 

 

 

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

 

  • 타입으로 조회 시 같은 타입의 스프링 빈이 둘 이상이면 오류 발생 -> 빈 이름 지정
  • ac.getBeansOfType()을 사용하면 해당 타입의 모든 빈을 조회할 수 있다.

 


    @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);
    }
복사했습니다!