애플리케이션 코드를 작성할 때, 특정기능이 필요하면 라이브러리를 호출하여 사용하곤 한다. 프로그램의 흐름을 제어하는 주체가 애플리케이션 코드가 된다. 하지만 프레임워크 기반의 개발에서는 프레임워크 자신이 흐름을 제어하는 주체가 되어 필요할 때마다 애플리케이션 코드를 호출하여 사용한다.
프레임워크에서 이 제어권을 가지는 것이 바로 컨테이너(Container)다.
객체에 대한 제어권이 개발자로부터 컨테이너에게 넘어가면 객체의 생성부터 생명주기 관리까지의 모든것을 컨테이너가 도맡아서 하게된다. 이를 일반적인 제어권의 흐름이 바뀌었다고 하여 IoC 제어의 역전이라고 부른다.
컨테이너란?(Container)
컨테이너는 인스턴스의 생성부터 소멸까지 생명주기를 관리하며, 생성된 인스턴스에게 추가적인 기능을 제공한다.
예를 들어, 서블릿을 실행해주는 WAS는 서블릿 컨테이너를 가지고 있다.
WAS는 웹브라우저로부터 서블릿 URL에 해당하는 요청을 받으면 서블릿을 메모리에 로드한 후 실행한다.
서블릿 클래스는 개발자가 작성했지만, 실제로 메모리에 올리고 실행하는 것은 WAS가 가지고 있는 서블릿 컨테이너가 한다.
서블릿 컨테이너는 동일한 서블릿에 해당하는 요청을 받으면 또 메모리에 올리지 않고 기존에 메모리에 올라간 서블릿을 실행하여 그 결과를 웹 브라우저에게 전달한다.
이렇듯 컨테이너는 인스턴스의 생명주기를 관리하며 생성된 인스턴스들에게 추가적인 기능을 제공하는 것을 말한다.
IoC(제어의 역전) 이란?
컨테이너가 코드 대신 오브젝트의 제어권을 가지고 있어 이것을 IoC(제어의 역전)이라 한다.
예를 들어, 서블릿 클래스는 개발자가 코딩하지만 그 서블릿의 메소드를 알맞게 호출하는 것은 WAS가 한다.
이렇게 개발자가 만든 어떤 클래스나 메소드를 다른 프로그램이 대신 실행해주는 것을 제어의 역전이라고 한다.
DI(Dependency Injection 의존성 주입)
DI는 의존성 주입이란 뜻을 가진다.
이는 클래스 사이의 의존관계(클래스내에서 다른 클래스를 생성한다던가 또는 다른 객체의 메소드를 사용하는 등)를 컨테이너가 빈(Bean) 설정 정보를 바탕으로 자동으로 연결해주는 것을 말한다.
개발자는 제어를 담당할 필요없이 Bean 설정파일에 의존관계가 필요하다는 정보만 추가해주면된다. 그러면 오브젝트 레퍼런스를 외부(Container)로부터 주입받아서, 실행시에 동적으로 의존관계가 생성된다.
참고로 스프링 IoC 컨테이너가 관리하는 객체를 빈(Bean)이라고 부른다. 그래서 스프링에서는 빈들을 관리한다는 의미로 컨테이너를 빈 팩토리(Bean Factory) 라고 부른다. 하지만 스프링은 DI 작업 그 이상으로 애플리케이션을 개발하는데 필요한 여러가지 컨테이너 기능을 하기 떄문에 애플리케이션 컨텍스트(Application Context)라고 부르기도 한다. 스프링에서는 이러한 컨테이너를 일반적으로 구성(Configuration)정보를 담아 xml로 구성한다.
DI가 적용되지 않은 예를 보자
class Engine {
}
class Car {
Engine e = new Engine();
e.execute();
}
의존성 주입이 적용되지 않으면 위 코드처럼 개발자가 클래스 내 직접 인스턴스를 생성하는 코드를 작성해주어야 한다.
다음은 스프링에서 DI가 적용된 예이다.
@Component
class Engine {
}
@Component
class Car {
@Autowired
Engine e;
e.execute();
}
위의 예시는 어노테이션을 이용하여 빈을 설정하고있다.
IoC 컨테이너가 Engine 인스턴스를 생성하여 Car 인스턴스에게 주입해주고 있다. 개발자가 코드에 인스턴스가 생성되는 부분을 작성하지 않게된다.
IoC/DI가 적용될 경우, 우선 사용할 객체들을 컨테이너에 등록하는 작업이 필요하다. XML에 설정하거나 어노테이션을 이용하는 방법이있다.
IoC/DI를 사용하면 객체를 생성할 때 해당 객체가 참조하고있는 다른 객체에 대한 종속성을 애플리케이션 코드 외부(컨테이너)에 설정하게 함으로써 결합도(coupling)는 낮추면서 유연성과 확장성은 향상시킬 수 있다.
스프링에서 제공하는 IoC/DI 컨테이너
- BeanFactory : IoC/DI에 대한 기본 기능을 가지고 있다.
- ApplicationContext : BeanFactory의 모든 기능을 포함한다. 일반적으로 BeanFactory보다는 ApplicationContext를 사용하는것이 더 추천된다. 트랜잭션처리, AOP 등에 대한 처리를 할 수 있다.
- BeanPostProcessor : 컨테이너의 기본 로직을 오버라이딩하여 인스턴스화와 의존성 처리 로직 등을 개발자가 원하는대로 구현할 수 있도록한다.
- BeanFactoryPostProcessor : 설정된 메타 데이터를 커스터마이징할 수 있다.
참고
'Spring Framework' 카테고리의 다른 글
| 클라이언트 요청 처리 순서 (0) | 2022.01.28 |
|---|---|
| 핸들러 인터셉터(Interceptor) (0) | 2022.01.28 |
| Properties 값 져올때 오류 (0) | 2022.01.14 |
| DispatcherServlet과 MVC 아키텍쳐 (0) | 2022.01.12 |