스프링 기본 sec4. 스프링 컨테이너와 스프링 빈

고라니·2021년 9월 8일
0

스프링기본

목록 보기
4/5

지금까지는 자바 객체지향의 다형성만을 이용하여 코드를 짤 때 DIP, OCP를 왜 지킬 수 없고, 이를 어떻게 해결했는지 공부하였다.
이번 섹션부터는 스프링 컨테이너의 장점들을 더 공부할 것이다.
모든 내용, 자료 출처는 인프런 김영한님 스프링 기본 강의입니다.

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

1. 스프링 컨테이너 생성

new AnnotationConfigApplicationContext(AppConfig.class);
스프링 컨테이너를 생성할 때는 구성 정보를 지정해 주어야한다.
수업에서는 AppConfig.class 를 구성 정보로 지정함.

2. 스프링 빈 등록

스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
(@Bean) 찾아서 싹 다 호출 하고, 스프링 컨테이너의 스프링 빈 저장소에
key : value ( 빈 이름 : 빈 객체 ) 형태로 저장

3. 스프링 빈 의존관계 설정 및 완료

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

컨테이너에 등록된 빈 조회

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

ac.getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회한다.
ac.getBean() : 빈 이름으로 빈 객체(인스턴스)를 조회한다.
ac.getBeanDefinition() : Bean에 대한 meta data 정보들을 반환한다. 코드에서는 스프링이 내부에서 사용하는 빈을 getRole() 로 구분하기 위해 사용함.

  • ROLE_APPLICATION : 일반적으로 사용자가 정의한 빈
  • ROLE_INFRASTRUCTURE : 스프링이 내부에서 사용하는 빈

스프링 빈 조회 - 기본

테스트 코드로 기본적인 빈 조회를 해본다.
같은 타입이 여러 개 있는 경우 등등을 제외한 기본 코드이다.

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

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

@Test
void 구체_타입으로_조회() {
 	MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
 	assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
 //(권장하지않음 : 유연성이 떨어짐 + 역할에 의존하라)
}

@Test
void 빈이름으로_조회실패"() {
	assertThrows(NoSuchBeanDefinitionException.class,
                () -> ac.getBean("XX", MemberService.class));
}  // 실행 시 예외가 NoSuch~...클래스면 성공 (예외 발생해야 성공)

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

동일 타입이 둘 이상일 경우 다음과 같이 예외가 발생하게 됨. 이때는 빈 이름까지 지정하면 된다.

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memberRepository1,memberRepository2

+ac.getBeansOfType()을 사용하면 해당 타입의 모든 빈을 조회할 수 있다.
(반환형 : Map) 적절히 만져서 활용 및 사용 가능

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

스프링 빈 조회 - 상속 관계

대 원 칙

부모 타입으로 조회하면, 자식 타입도 함께 조회한다.

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

따라서 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.

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

실제로 ApplicationContext에서 직접 getBean()을 쓸 일은 별로 없다. 뒤에 가면 스프링 컨테이너가 자동으로 의존관계 주입해주는 것을 쓰기 때문.
그런데 가끔 순수 java에서 spring container를 써야할 때나, 자동 주입에서 이해가 쉽기 위해선 꼭 알아야 한다. (부모 타입 호출 시 자식 타입 모두 딸려오는 이런 내용들)

BeanFactory와 ApplicationContext

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스 / 스프링 빈을 관리하고 조회하는 역할을 담당한다.
  • 앞서 사용한 getBean() 등 모두 해당 인터페이스가 제공하는 기능이다.

ApplicationContext

  • BeanFactory 기능을 모두 상속받아서 제공
  • 빈을 관리하고 검색하는 기능을 BeanFactory가 제공해주는데, 그러면 둘의 차이가 뭘까?
    애플리케이션을 개발할 때에는 빈을 관리하고 조회하는 기능은 물론이고, 수 많은 부가기능이 필요하다.

    ApplicationContext 인터페이스는 그림과 같이 여러 인터페이스들을 상속한다.
    각 인터페이스의 기능이 궁금하면 검색해보기.

정리

  • ApplicationContext는 빈 관리기능(BeanFactory)과 더불어 편리한 부가 기능을 제공한다.
  • BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 ApplicationContext를 사용한다.
  • BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.

다양한 설정 형식 지원 - 자바 코드, XML

최근에는 스프링 부트를 많이 사용하면서 XML기반의 설정은 잘 사용하지 않는다.
아직 많은 레거시 프로젝트 들이 XML로 되어 있고, 또 XML을 사용하면 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점도 있으므로 한번쯤 봐두는 것도 괜찮다고 한다.
코드 관련해서 궁금하면 PDF를 다시 볼것~

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

스프링은 어떻게 다양한 설정 형식을 지원는가?

각 ApplicationContext 구현체들의 final 필드인 xxxBeanDefinitionReader가
java code 및 xml을 읽고 번역하여 BeanDefinition이라는 단일 표현체를 만든다.
BeanDefinition은 여러 정보를 가지고 있는데, 필요 시 pdf를 참고한다.

BeanDefinition에 대해서는 너무 깊이있게 이해하기 보다는, 스프링이 다양한 형태의 설정 정보를
BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하면 된다.

profile
공부를 열심히 하는 학부생

0개의 댓글