스프링 컨테이너란?

gorapaduckoo·2023년 6월 25일
0

스프링 기본편

목록 보기
4/10
post-thumbnail

인프런 김영한님의 스프링 핵심 원리 - 기본편 강의 내용을 바탕으로 작성한 글입니다.


이전 글에서 AppConfig처럼 DI와 IoC를 해주는 것을 DI 컨테이너라고 부른다는 이야기를 했었다. 이번에는 스프링에서 DI와 IoC를 제공하는 스프링 컨테이너에 대해 알아보자.

1. 스프링 컨테이너란?

스프링 컨테이너는 컨테이너에 등록된 객체들의 생명 주기를 관리하고, 객체들에게 추가적인 기능을 제공한다. 스프링 빈으로 등록된 객체들의 인스턴스를 생성하고, 스프링 빈 사이에 의존관계를 주입하는 게 바로 스프링 컨테이너의 역할이다. 이전 글에서 보았던 AppConfig의 역할을 담당한다고 보면 된다.

그렇다면 기존의 AppConfig와는 뭐가 다르길래 굳이 스프링 컨테이너를 쓰는 걸까?



2. 스프링 컨테이너 설정 정보 구성하기

물론 스프링 컨테이너라고 해서 처음부터 무슨 클래스에 무슨 구현체가 필요한지에 대해 알고있는 건 아니다. 때문에 어떤 객체를 생성할지, 그리고 어떤 클라이언트에 어떤 구현체를 넣어줄지에 대해서, 즉 설정 정보는 프로그램을 짜는 우리가 직접 알려주어야 한다. 스프링 컨테이너는 아래와 같이 다양한 설정 형식을 지원한다.

(1) 애노테이션 기반 자바 코드로 설정하기

먼저 설정 정보를 클래스에 담아 전달하는 방법이다.

@Configuration
public class AppConfig {
	
    @Bean
	public OrderService orderService() {
    	return new OrderServiceImpl(discountPolicy());
    }
    
    @Bean
    public DiscountPolicy discountPolicy() {
    	return new FixDiscountPolicy();
    }
}

이전의 AppConfig에 몇가지 애노테이션을 추가한 상태이다.

스프링 컨테이너는 @Configuration이 붙은 클래스를 설정 정보로 사용한다. 그리고 설정 정보 클래스에서@Bean 애노테이션이 달린 메서드를 모두 호출한 뒤, 반환된 인스턴스를 컨테이너 안에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체들을 스프링 빈이라고 한다.

스프링 빈은 기본적으로 @Bean이 붙은 메서드의 이름을 자신의 이름으로 사용한다. 위의 코드를 예로 들어보자면, discountPolicy라는 이름의 빈은 FixDiscountPolicy 인스턴스를 갖고 있다.

(2) 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="orderService" class="hello.core.order.OrderServiceImpl">
        <constructor-arg name="discountPolicy" ref="discountPolicy"/>
    </bean>

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

XML로 설정할 때는 <constructor-arg>태그를 통해 생성자에 필요한 매개변수를 넘겨주면 된다. ref="discountPolicy"에서는 id가 discountPolicy인 빈을 찾아 주입해준다.



3. 스프링 컨테이너 생성하기

이제 설정 정보를 넘겨 스프링 컨테이너를 생성해보자.
애노테이션 기반 자바 코드로 설정하는 방법을 더 자주 사용하므로, 자바 코드 설정을 기반으로 살펴보겠다.

// 애노테이션 기반 자바 코드로 설정했을 때 
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

// xml 파일로 설정했을 때
ApplicationContext applicationContext = new GenericXmlApplicationContext(appConfig.xml);

new AnnotationConfigApplicationContext(AppConfig.class);를 통해 스프링 컨테이너 ApplicationContext가 생성된다. ApplicationContext는 인터페이스, AnnotationConfigApplicationContext는 구현 클래스로, 구현 클래스의 생성자에 설정 클래스를 매개변수로 넘겨주면 설정 정보를 기반으로 스프링 컨테이너가 생성된다.

스프링 컨테이너 안에는 스프링 빈 저장소라는게 존재하는데, 스프링 빈 저장소에는 Map<String, Object> 같은 느낌으로 빈 이름과 그에 대응되는 빈 객체가 저장되어 있다. 스프링 컨테이너는 AppConfig.class에서 @Bean이 달린 메서드를 전부 호출하여 메서드명을 빈 이름으로, 반환 객체를 빈 객체로 하여 저장소에 스프링 빈을 등록한다. 이 때 주의해야 할 점은, 빈 이름은 중복되면 안된다.

그리고 마지막으로 설정 정보를 참고해서 의존관계를 주입해주면 스프링 컨테이너의 생성이 완료된다. AppConfig를 예로 들자면, orderService에게 discountPolicy를 주입해주는 것이다.



4. 스프링 컨테이너에서 빈 조회하기

@Configuration
public class AppConfig {
	
    @Bean
	public OrderService orderService() {
    	return new OrderServiceImpl(discountPolicy());
    }
    
    @Bean
    public DiscountPolicy discountPolicy() {
    	return new FixDiscountPolicy();
    }
}

public class Main {
	public static void main(String args[]) {
    	ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        OrderService orderService = applicationContext.getBean("orderService");
        orderService.createOrder();
        ...
    }
}

스프링 컨테이너에 등록된 빈은 applicationContext.getBean() 메서드를 통해 조회할 수 있다. 개발자는 스프링 컨테이너에서 필요한 객체를 찾아와서 사용하면 된다. getBean(빈이름, 타입) 형식으로 이름과 타입을 통해 조회할 수도 있고, getBean(타입) 처럼 타입으로만 조회할 수도 있다.

단, 타입으로 조회하는 경우 부모 타입으로 조회하면 그 자손 타입까지 전부 조회된다. 예를 들어, DiscountPolicy 타입으로 조회하면 FixDiscountPolicyRateDiscountPolicy 타입의 빈까지 조회된다는 말이다. 만약 조회할 빈이 없거나, 타입으로 조회했을 때 같은 타입의 빈이 2개 이상이면 오류가 발생하므로 주의해야 한다.



참고: https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html

0개의 댓글