반응형

# 스프링 컨테이너와 스프링 빈

## BeanFactory 와 ApplicationContext

  • 최상위 컨테이너인 BeanFactory (인터페이스) 존재하고 그걸 상속받는 ApplicationText (인터ApplicationContextㅔ이스) 존재.

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스.
  • 역할 : 스프링 빈 관리, 조회
  • getBean() 제공.
  • BeanFactory 를 직접 사용할 일은 거의 없고, 주로 ApplicationContext 를 사용.

ApplicationContext

  • BeanFactory 의 기능을 모두 상속받아 제공.
  • BeanFactory 와 차이점 : AppicationContext의 경우 BeanFactory  뿐만 아니라 MessageSource (인터페이스), EnvironmentCapable (인터페이스), ApplicationEventPublisher (인터페이스), ResourceLoader (인터페이스) 등의 기능을 상속받음.
  • 메시지 소스를 활용한 국제화 기능 : 접속 국가에 따른 언어로 출력.
  • 환경변수 : 로컬, 개발, 운영 등을 구분하여 처리.
  • 애플리케이션 이벤트 : 이벤트를 발행, 구독하는 모델을 편리하게 지원함.
  • 편리한 리소스 조회 : 파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회.

## 다양한 설정 형식 지원 (자바 코드, XML)

  • 스프링 컨테이너의 경우 다양한 형식의 설정 정보를 받아드릴 수 있도록 유연하게 설계되어 있음. (자바 코드, XML, Groovy 등)
  • ApplicationText를 구현한 것에는 아래와 같은 것들이 존재.

1. 애노테이션 기반 자바코드 설정 사용 (AppConfig.class)

  • AnnotationConfig (ApplicationContext)
  • new AnnotationConfigApplicationContext(AppConfig.class)
  • AnnotationConfigApplicationContext 클래스를 사용하면서 자바 코드로된 설정 정보 넘김.

2. XML 설정 사용 (appConfig.xml)

  • GenericXml ApplicationContext
  • 최근에는 거의 사용하지 않음.
  • 레거시 프로젝트에서 사용.
  • 장점 : XML 사용 시 컴파일 없이 빈 설정 정보 변경 가능.
  • GenericXmlApplicationContext 를 사용하면서 xml 설정 정보 넘김.

3. appConfig.xxx (임의 설정)

  • Xxx ApplicationContext

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>

XmlAppContext : xml 관련 Test 코드.

package hello.core.xml;

import hello.core.member.MemberService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

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 기반 appConfig.xml 과 자바 코드로 된 AppConfig.java 가 거의 비슷함. (xml 기반의 설정은 거의 사용하지 않음)  

## 스프링 빈 설정 메타 정보 (BeanDefinition)

  • 스프링 컨테이너는 자바 코드, XML 인지 몰라도 BeanDefinition (빈 설정 메타정보) 만 알면 된다. (스프링 컨테이너는 BeanDefinition (인터페이스) 에만 의존)
  • @Bean, <bean> 을 사용하게되면 각각 하나씩 메타 정보가 생성된다. (스프링 컨테이너의 경우 해당 메타 정보를 바탕으로 스프링 빈을 생성)
  • AnnotationConfigApplicationContext 의 경우 내부에 AnnotatedBeanDefinitionReader 를 사용, AppConfig.class를 읽고, BeanDefinition 생성.
  • GenericXmlApplicationContext 의 경우 내부에 XmlBeanDefinitionReader 를 사용, appConfig.xml 를 읽고, BeanDefinition 생성.

BeanDefinitionTest 

package hello.core.beandefinition;

import hello.core.AppConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class BeanDefinitionTest {

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName("빈 설정 메타정보 확인 Test")
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                System.out.println("beanDefinitionName = " + beanDefinitionName
                        + "beanDefinition = " + beanDefinition);
            }
        }
    }
}
  • 실무에서 BeanDefinition 을 직접 정의하거나 사용할 일은 거의 없음.
반응형

+ Recent posts