
스프링 컨테이너란?
스프링 컨테이너는 빈이라고 불리는 자바 객체를 등록하여 생성부터 소멸까지 관리해 주는 공간이다.
스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 하며 스프링 컨테이너의 구성 정보는 xml을 기반으로 만들 수도 있고, 어노테이션을 이용해 자바 설정 클래스로 만들 수도 있으며, Groovy를 이용해서도 만들 수가 있다.
아래 내용을 통해 xml 기반과 어노테이션을 이용하여 만든 스프링 컨테이너를 비교해 보자
- xml 기반의 스프링 컨테이너
- 최근에는 스프링 부트를 많이 사용하면서 xml 기반의 설정은 잘 사용하지 않는다.
- 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>
- 어노테이션을 이용한 자바 설정 클래스
- 스프링 컨테이너를 생성할 때는 구성 정보를 지정해주어야 한다.(현재 예시에서는 아래 AppConfig.class를 구성 정보로 지정했다.)
- 스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보를 사용해 스프링 빈을 등록한다.(@Bean 이용하여 빈 등록)
- 스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입한다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
스프링 컨테이너의 생성 과정
이번에는 스프링 컨테이너의 생성 과정을 단계별로 이미지를 참고해서 살펴보려 한다.
1. 스프링 컨테이너 생성

스프링 컨테이너 생성 시에는 new AnnotationConfigApplicationContext(AppConfig.class)를 호출하여 스프링 컨테이너를 생성하며, 해당 이미지에서는 스프링 컨테이너를 생성시에 전달 받은 AppConfig.class의 구성 정보를 가져와서 스프링 빈을 등록해준다.
2. 스프링 빈 등록

스프링 컨테이너는 파라미터로 넘어온 설정 클래스 정보(AppConfig.class)를 사용해서 스프링 빈을 등록한다.
이때 빈의 이름은 메서드 이름을 사용하지만 name 속성을 이용해 빈 이름을 직접 부여할 수도 있다.(ex. @Bean(name="member2")) 여기서 빈 이름을 직접 지정할 때는 항상 다른 이름을 부여해야 한다. 같은 이름을 부여할 경우 다른 빈이 무시되거나, 기존 빈을 덮어버리거나 설정에 따라 오류가 발생할 수도 있다.
3. 스프링 빈 의존관계 설정

스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입한다.
위의 이미지에서는 memberService와 orderService를 생성하기 위해 memberRepository, discountPolicy와의 의존관계가 필요한데 이러한 정보를 AppConfig.class를 통해 빈에 등록했기 때문에 의존관계가 주입된다.
* 스프링은 빈을 생성하고, 의존관계를 주입하는 단계가 나누어져 있지만 자바 코드로 빈을 등록하면 생성자를 호출하면서 의존관계 주입도 한 번에 처리가 된다.
BeanFactory VS ApplicationContext
스프링 컨테이너를 부를 때 BeanFactory, ApplicationContext로 구분해서 이야기하며, BeanFactory를 직접 사용하는 경우는 거의 없고 ApplicationContext를 주로 스프링 컨테이너라고 부른다. 그렇다면 BeanFactory와 ApplicationContext의 차이점을 살펴보도록 하자
- BeanFactory
- 스프링 컨테이너의 최상위 클래스이다.
- 스프링 빈을 관리하고 조회하는 역할을 담당한다.
- getBean()을 제공한다.
- ApplicationContext
- BeanFactory의 기능을 모두 상속받아서 사용한다.
- 빈을 관리하고 조회하는 기능에 추가적으로 부가기능을 제공한다.
- 메시지 소스를 활용한 국제화 기능
- 환경변수
- 애플리케이션 이벤트
- 편리한 리소스 조회
스프링 빈 설정 메타 정보 - BeanDefinition
스프링이 이렇듯 다양한 방법으로 설정 형식을 지원할 수 있는 이유는 빈 설정 메타정보라 불리는 BeanDefinition이라는 추상화 덕분이다. 스프링은 설정 형식이 xml이 되었든, 자바 코드가 되었든 형식을 몰라도 된다. xml과 자바 코드를 읽어서 만들어진 BeanDefinition만 알면 된다. 이러한 빈 설정 메타정보인 BeanDefinition는 xml에서는 <bean> 그리고 자바 코드에서는 @Bean 하나당 하나의 메타 정보를 생성하며 스프링은 이 메타 정보를 기반으로 스프링 빈을 생성한다.
아래 테스트 코드 2가지를 통해 xml과 자바 코드를 이용한 빈 설정 정보를 확인해 보자
1. xml
public class BeanDefinitionTest {
GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
@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);
}
}
}
}
결과

2. 자바 코드
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의 정보
- BeanClassName: 생성할 빈의 클래스 명(자바 설정처럼 팩토리 역할의 빈을 사용하면 없음)
- factoryBeanName: 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig
- factoryMethodName: 빈을 생성할 팩토리 메서드 지정, 예) memberService
- Scope: 싱글톤(기본값)
- lazyInit: 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때까지 최대한 생성을 지연처리 하는지 여부
- InitMethodName: 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명
- DestroyMethodName: 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명
- Constructor arguments, Properties: 의존관계 주입에서 사용한다. (자바 설정처럼 팩토리 역할의 빈을 사용하면 없음)
출처 : 인프런 우아한 형제들 최연소 기술이사 김영한의 스프링 완전 정복(스프링 핵심원리 - 기본 편)
'Development > Spring' 카테고리의 다른 글
| [Spring] 빈 생명주기 콜백 (0) | 2023.03.23 |
|---|---|
| [Spring] 의존관계 자동 주입 (0) | 2023.03.19 |
| [Spring] @Component와 컴포넌트 스캔 (0) | 2023.03.18 |
| [Spring] 스프링 컨테이너에 등록된 스프링 빈 조회 (0) | 2023.03.12 |
| [Spring] 싱글톤 패턴과 싱글톤 컨테이너 (0) | 2023.03.01 |