스프링 컨테이너와 빈

최주영·2024년 3월 14일
0

스프링 핵심 원리

목록 보기
4/9
post-custom-banner

✅ 스프링 컨테이너

  • ApplicationContext 로 인터페이스 이다
  • XML 기반 또는 애노테이션 기반의 자바 설정 클래스로 만들 수 있다
  • 스프링 컨테이너 생성
  • 스프링 빈 등록
  • 빈 이름을 직접 부여할 수 있지만, 항상 다른 이름을 부여하자!
    @Bean(name="memberService2)
  • 스프링 빈 의존관계 설정 - 준비
  • 스프링 빈 의존관계 설정 - 준비 완료

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

스프링 빈 조회 - 기본

  • getBeanDefinitionNames() : 스프링에 등록된 모든 빈 이름을 조회
  • getBean(빈이름, 타입) : 빈 이름으로 객체를 조회
  • getBean(타입) : 타입만으로도 가능
  • 조회 대상 스프링 빈이 없으면 예외 발생 -> NoSuchBeanDefinitionExcpetion
 public class ApplicationContextBasicFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 이름으로 조회")
    void findByName(){
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);  // 타입이 동일하면 true
    }

    @Test
    @DisplayName("이름 없이 타입으로 조회")
    void findByType(){
        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);  // 타입이 동일하면 true
    }

    @Test
    @DisplayName("구체 타입으로 조회")
    void findByName2(){
        MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class); // 타입이 동일하면 true
    }

    @Test
    @DisplayName("빈 이름으로 조회X")
    void findByNameX(){ // 예외 발생
        assertThrows(NoSuchBeanDefinitionException.class,
                () -> ac.getBean("xxxxx", MemberService.class));
    }
}

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

  • 타입으로만 조회시, 둘 이상이면 오류 발생 -> 빈 이름 지정

  • getBeansOfType()를 사용하면 해당 타입의 모든 빈을 조회할 수 있음

    public class ApplicationContextSameBeanFindTest {
    
       AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);
    
       @Test
       @DisplayName("타입으로 빈 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다")
       void findBeanByTypeDuplicate() {
           assertThrows(NoUniqueBeanDefinitionException.class,
                   () -> ac.getBean(MemberRepository.class));
       }
    
       @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);
       }
     }

스프링 빈 조회 - 상속관계

  • 부모타입으로 조회하면, 자식 타입도 함께 조회됨
  • 그래서 모든 자바 객체의 최고 부모인 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)); 
            // 스프링부트안에 있는 모든 빈들이 다 조회됨
        }
    }

BeanFactoryApplicationContext


BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스
  • 스프링 빈을 관리하고 조회하는 역할을 담당
  • getBean() 을 제공
  • 위에서 사용했던 대부분의 기능은 BeanFactory가 제공하는 기능임
  • BeanFactory를 직접 사용할 경우는 거의 없음

ApplicationContext

  • BeanFactory 기능을 모두 상속받아서 제공
  • 애플리케이션을 개발할 때는 빈을 관리하고 조회하는 기능은 물론, 수 많은 부가기능이 필요함

수 많은 부가 기능이 필요하기 때문에 따로 인터페이스를 만들어서 기능추가를 함-> ApplicationContext
ApplicationContext = 빈 관리기능 + 편리한 부가 기능

그러므로 BeanFactoryApplicationContext 를 모두 스프링 컨테이너 라고 한다

  • MessageSource : 메세지 소스를 활용한 국제화 기능
    -> 한국에서 들어오면 한국어로, 영어권에서 들어오면 영어로
  • EnvironmentCapable : 환경 변수
    -> 로컬, 개발, 운영 등을 구분해서 처리
  • ApplicationEventPublisher : 애플리케이션 이벤트
    -> 이벤트를 발행하고 구독하는 모델을 편리하게 지원
  • ResourceLoader
    -> 파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회

✅ 다양한 설정 형식 지원

  1. 자바 코드
  2. XML 문서 설정
  3. 임의로 구현해서 만들기

    요즘은 XML 보다 자바 코드설정으로 많이 한다
    하지만 XML 은 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점이 있어서 배워두면 좋다
    추가로 많은 레거시 프로젝트들이 XML 로 되어있다
  • XmlAppConfig 사용 자바 코드
    -> GenericXmlApplicationContext를 사용하면서 xml 설정 파일을 넘기면 된다
public class XmlAppContext {
    @Test
    void xmlAppContext() {
        ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
    }
}
  • xml 기반의 스프링 빈 설정 정보 (경로 : src/main/resources/appConfig.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="memberService" class="hello.core.member.MemberServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository" />
    </bean>

    <bean id="memberRepository" class="hello.core.member.MemoryMemberRepository" />

    <bean id="orderService" class="hello.core.order.OrderServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository" />
        <constructor-arg name="discountPolicy" ref="discountPolicy" />
    </bean>

    <bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy" />

</beans>

-> 이러한 다양한 형식을 지원하는 이유의 중심에는 BeanDefintion 이라는 추상화가 있기 때문이다
스프링 컨테이너는 자바코드인지, XML인지 몰라도 되며, 오직 BeanDefinition만 알면 된다

  • BeanDefinition 정보
profile
우측 상단 햇님모양 클릭하셔서 무조건 야간모드로 봐주세요!!
post-custom-banner

0개의 댓글