Study

IOC 컨테이너(ApplicationContext 와 BeanFactory)

승톨이 2024. 2. 5. 10:19


IOC 개요 및 IOC 컨테이너


IOC 컨테이너는 IOC 원칙의 Spring Framework 구현이다. IOC 개요는 다음과 같다.

더보기

IOC (Inversion Of Control)

IOC 는 Inversion Of Control 의 약자로, 직역하여 제어의 역전 이라는 뜻이 된다. 즉 IOC 는 현재 코드의 흐름을 코드 내에서 제어하지 않고 외부에서(스프링의 경우 IOC 컨테이너에서) 제어하는 것을 말한다. (프레임워크가 IOC 가 반영된 기술의 대표적인 사례이기 때문에, 흔히들 프레임워크에서 개발자 코드를 호출하며 제어하는 것을 예로 들어 설명하곤 한다)  이렇게 설명하면 "컨트롤을 역전시키는 어떤 기술" 처럼 들릴 수 있으나, 여기서 말하는 IOC 는 따라야 하는 "원칙" 이다. 이 IOC 를 따르기 위해 스프링에서는 IOC 컨테이너(스프링 컨테이너)를 사용하며 DI와 같은 디자인 패턴을 사용한다.
그렇다면

"의존 역전 원칙(IOC) 을 따르는 방법으로, 코드 내부가 아닌 외부에서 흐름을 제어하기 위해 스프링은 IOC 컨테이너를 사용하며, 그 핵심 전략으로 종속성을 주입하는 디자인 패턴인 DI(Dependency Injection)를 사용한다."

라고 대략적인 흐름을 생각해 볼 수 있다.
IOC 와 DI 는 스프링의 핵심 가치 중의 하나이다. 스프링에서 IOC 원칙을 구현하는 IOC 컨테이너는 스프링 프레임워크의 기술 중 가장 핵심 기술이라고 봐도 되며, 스프링의 또다른 핵심 가치 중의 하나인 Spring AOP(Aspect Oriented Programming, 관점 지향 프로그래밍) 와도 밀접하게 연관되어 있다. 일반적으로 '스프링 컨테이너' 라 함은 IOC 컨테이너와 같은 의미로 사용되는데, 여기서는 IOC의 개념과 IOC 컨테이너에 대해 정리해 보고자 한다.

 

즉 스프링 프레임워크는 IOC 원칙 실현을 위해 IOC 컨테이너를 사용하고 이는 스프링 컨테이너와 같은 의미로 사용된다.

스프링은 ApplicationContext 와 BeanFactory 라는 두 종류의 컨테이너를 제공한다.
BeanFactory 는 org.springframework.beans.factory.BeanFactory 인터페이스를 확장한 클래스의 인스턴스이고, ApplicationContext 는 BeanFactory 인터페이스를 확장한 org.springframework.context.ApplicationContext 인터페이스를 확장한 클래스의 인스턴스이다. 

스프링 컨테이너(=IoC 컨테이너)

빈 팩토리(org.springframework.beans.factory.BeanFactory) 인터페이스 또는 어플리케이션 컨텍스트(org.springframework.context.ApplicationContext) 인터페이스를 확장한 클래스의 인스턴스



BeanFactory 는 스프링 컨테이너의 기본적인 형태이다. 빈들의 생성, 관리, 생명주기와 의존관계를 관리하는 등 객체와 관련된 기능을 담당한다. 빈의 사용 요청이 있는 시점에 빈을 인스턴스화 하는 지연로딩 (Lazy-Loading) 을 사용한다. 요즘에는 BeanFactory 를 직접 사용하는 일은 거의 없고, 대부분 BeanFactory 를 확장한 ApplicationContext 의 하위 인터페이스를 사용한다.

ApplicationContext 는 빈 팩토리의 하위 인터페이스이기 때문에 빈 팩토리의 모든 기능을 제공하며, 추가적으로 AOP 지원, 이벤트 처리, 국제화를 위한 메세지 처리, 웹 어플리케이션 지원 등 여러 가지 기능을 포함한다. 어플리케이션 컨텍스트는 어플리케이션 시작 시점에 설정 정보에 저장된 구성 메타데이터를 읽어 등록된 모든 빈을 인스턴스화 하는 사전 로딩(Pre-Loading) 방식을 사용한다.

 

 

스프링 컨테이너의 구성 방식


컨테이너를 구성한다는 것이 무슨 뜻일까?

스프링 어플리케이션은 어플리케이션 클래스와 구성 메타데이터가 결합되어 어플리케이션 컨텍스트를 생성한다. 구성 메타데이터라는 것은 스프링 어플리케이션의 설정 정보를 나타내는 말인데, 풀어서 얘기하면 빈으로 등록될 객체의 정의, 의존관계, 프로퍼티 설정 등 어플리케이션의 동작 흐름을 결정하는 정보들을 말한다. 스프링 컨테이너는 우리가 작성한 어플리케이션 클래스와 이 구성 메타데이터를 읽어와서 어플리케이션 컨텍스트를 생성하고, 비로소 실행 가능한 어플리케이션이 된다. 이 관계를 그림으로 설명하면 다음과 같다.

출처 : Spring 공식 문서

 

스프링 초기에는 xml 설정 파일을 사용해서 구성 메타데이터를 표현했다. 스프링 컨테이너는 xml 설정 파일을 읽어 와서 컨텍스트를 구성하는 방식을 사용해 왔다. 이후에 xml 기반 구성 방식의 대안으로 Annotation 기반 구성 방식, Java 기반 구성 방식이 등장했는데, 이들은 xml 로만 구성 정보를 명시하지 않고 자바 클래스 내에서, 또는 어노테이션(주석) 을 사용해서 구성 정보를 전달하는 방법을 제공함으로써 프로그래머가 보다 편하게, 선택적으로 구성 정보를 설정할 수 있도록 도움을 준다. 현재는 xml 을 사용한 컨테이너 구성 방식보다 Annotation 이나 Java 를 기반으로 컨테이너를 구성하는 방식이 더 널리 쓰인다. 

그러나 늦게 등장했고 널리 쓰인다고 해서 반드시 더 좋은 구성 방식은 아니며, 각각 구성 방식에는 장단점이 존재한다. xml 구성 방식은 빈의 등록과 의존성 주입, 프로퍼티 설정 등이 세부적으로 명시되기 때문에 그만큼 작성이 복잡하고 번거로울 수 있지만, 대규모 프로젝트 등에서 복잡한 구성이 필요할 때 적절히 사용될 수 있다. 또 xml 파일로 따로 구성 정보를 작성하는 것은 코드를 건드리거나 따로 컴파일을 하지 않고도 구성 정보를 변경할 수 있으며, 구성이 분산화되지 않고 제어하기 쉽다는 장점이 있다. Annotation 기반 구성 방식과 Java 기반 구성 방식은 Java 코드 내에서 설정 클래스를 정의하거나 주석을 사용해서 구성 정보를 설정하는데, xml 방식에 비해 훨씬 짧고 간결하며 읽기 쉬운 구성 정보를 제공한다. 어떤 전략을 사용할지는 프로젝트 특성에 따라 개발자가 선택할 몫이다.

 

 

스프링 컨테이너의 인스턴스화


위에서 설명했듯 스프링 컨테이너는 스프링의 핵심 기술 중 하나이며, 결국 BeanFactory 인터페이스의 구현이기 때문에 자바 클래스라고 생각할 수 있다. 그러나 우리는 코드 어디에서도 컨테이너를 인스턴스화해서 접근하지 않는다. 이는 스프링에서 개발자가 컨테이너를 인스턴스하는 코드를 명시할 필요가 없기 때문이다. 예를 들어 고전적인 스프링 어플리케이션에서는 다음과 같이 web.xml 파일의 간단한 8줄 만으로 ApplicationContext 를 선언적으로 생성할 수 있다.


스프링 부트에서는 더 간단하게 @SpringBootApplication 어노테이션 및 그 내부 구현(SpringApplication)을 통해 ApplicationContext 를 자동 생성(인스턴스화) 및 초기화 한다. 이렇게 스프링에서는 개발자가 명시적으로 컨테이너를 인스턴스화 하지 않아도 컨테이너가 제공하는 많은 기능들을 사용할 수 있다.