꼬물꼬물
스프링 컨테이너와 스프링 빈 [다양한 설정 형식(XML), 메타정보] 본문
BeanFactory와 Application Context
- BeanFactory
- 스프링 컨테이너의 최상위 인터페이스
- 스프링 빈을 관리하고 조회하는 역할 담당
- getBean()으로 조회 가능
- ApplicationContext
- BeanFactory 기능을 모두 상속받는다. <- 그렇다면 둘의 차이는?
- 애플리케이션 개발에는 빈 관리/조회 기능 뿐만 아니라 많은 부가기능이 필요하다.
- 메시지 소스를 활용한 국제화 기능: 한국에서 들어오면 한국어로, 영어로 들어오면 영어로 출력한다.
- 환경 변수: 로컬(개발), 개발(테스트 서버), 운영(실제) 환경 등을 구분해 처리
- 애플리케이션 이벤트: 이벤트를 발행하고 구독하는 모델을 편리하게 지원
- 편리한 리소스 조회: 파일, 클래스 패스, 외부 등에서 리소스를 편리하게 조회
- 이는 애플리케이션 만드는데 필요한 공통 기능들
BeanFactory와 ApplicationContext 모두 스프링 컨테이너라고 할 수 있다.
다양한 설정 형식 지원 - 자바 코드, XML
- 스프링 컨테이너는 다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계되어 있다.
- 자바코드, XML, Groovy 등
- 어노테이션 기반 자바 코드 설정 사용
- new AnnotationConfigApplicationContext(AppConfig.class)
- AnnotationConfigApplicationContext 클래스를 사용하면 자바 코드로된 설정정보를 넘기면 된다.
- XML 설정 사용
- 최근 스프링 부트 사용하면서 XML 기반의 설정은 잘 사용하지 않음.그렇지만 아직 많은 레거시 프로젝트들이 XML로 되어 있고, XML을 사용하면 컴파일 없이 빈 설정 정보를 변경할 수 있는 장점이 있어 배워두자.
- 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);
}
}
resource/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">
<!-- class는 실제 구체 -->
<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">
<!-- ref는 참조 -->
<constructor-arg name="memberRepository" ref="memberRepository"/>
<constructor-arg name="discountPolicy" ref="discountPolicy"/>
</bean>
<bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy"/>
</beans>
스프링의 유연한 설정들을 확인할 수 있다.
스프링 빈 설정 메타 정보 - BeanDefinition
- 스프링은 어떻게 이런 다양한 설정 형식을 지원할까? <- BeanDefinition 추상화가 있다!
- 즉, 역할과 구현을 개념적으로 나눈 것.
- XML을 읽어서 BeanDefinition을 만든다.
- 자바 코드를 읽어서 BeanDefinition을 만든다.
- 스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 BeanDefinition만 알면 된다!
- BeanDefinition을 빈 설정 메타 정보라고 한다,
- @Bean, <bean> 당 각각 하나씩 메타 정보가 생성된다.
- 스프링 컨테이너는 이 메타 정보를 기반으로 스프링 빈을 생성한다.
- 스프링 컨테이너는 BeanDefinition에만 의존한다. -> 자바인지 xml인지 상관 안 해! <- 추상화에만 의존
- AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 사용해 AppConfig.class를 읽고 BeanDefinition을 생성한다.
- GernericXmlApplicationContext는 XmlBeanDefinitionReader를 사용해 appConfig.xml 설정 정보를 읽고 BeanDefinition을 생성한다.
- 새로운 형식의 설정 정보가 추가되면, XxxBeanDefinitionReader를 만들어 BeanDefinition을 생성한다.
BeanDefinition 정보
- scope=; : 할당 X == 싱글톤
- lazyInit=null; : 보통의 스프링 빈은 스프링 컨테이너가 뜰 때, 등록되지만 Lazy는 실제 사용하는 시점에 스프링 빈을 초기화 한다.
- 메타 정보를 기반으로 실제 인스턴스를 생성한다.
public class beanDefinitionTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("빈 설정 메타 정보 확인")
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을 직접 생성해 스프링 컨테이너에 등록할 수 있다. 하지만 BeanDefinition을 직접 정의하거나 사용할 일은 거의 없다.
- 스프링이 다양한 형태의 설정 정보를 BeanDefinition으로 추상화해 사용한다.