BoostCourse

Spring IoC/DI 컨테이너

Sh4869 2020. 3. 6. 20:20

학습 목표

  1. 컨테이너에 대한 개념을 이해한다.
  2. IoC에 대한 개념을 이해한다.
  3. DI에 대한 개념을 이해한다.

핵심 개념

  • Container
  • IoC (Inversion of Control)
  • DI (Dependency Injection)

컨테이너(Container)

컨테이너는 인스턴스의 생명주기를 관리한다. 간단한 컨테이너의 예로 우리가 사용했던 WAS인 톰켓을 들 수 있다. 우리가 Servlet을 만들고 실행시킬때, Servlet객체를 만들어 메모리에 올린적이 없다. 하지만 Servlet객체가 생성되어 돌아가는 이유는 톰켓이 그 작업을 대신 해주기 때문이다. 이렇게 객체에 대한 라이프사이클을 관리해주는 역할을 해주는 것이 컨테이너이다. 또한 컨테이너는 생성된 인스턴스들에게 추가적인 기능을 제공하는 역할도 가지고 있다.

IoC (Inversion of Control)

Inversion of Control의 약자로 제어의 역전을 의미한다. 개발자가 프로그램을 개발하다보면 프로그램의 흐름을 제어하는 코드를 작성하는데, 이 흐름의 제어를 개발자가 아니라 다른 프로그램이 제어하는 것을 IoC라고 한다. 이러한 방법을 쓰는 이유는 무엇일까? 간단한 예를들어 생각해보자. 우리가 TV가 필요하여 S사에서 TV와 리모콘을 샀다고 가정해보자.

여러분은 위의 그림과 같은 리모콘으로 S사의 TV를 제어하며 생활하고 있었다. 그러다 어느날 TV가 고장나게 되어 여러분은 새로운 제품인 L사의 TV를 사게 된다. 이때 L사의 TV와 리모콘은 다음과 같다.

극단적인 예이지만 요점은 리모콘이 너무나도 달라져서 처음에 사용법을 익히기 어렵다는 것이다. 즉, 어느정도 포멧이 정해져 있지 않으면, 새로 TV와 리모콘을 살때마다 불편함을 겪는 것이다. 이를 위해 시중의 리모콘들은 어느정도 디자인이 통일되어있다.

 

프로그래밍에서도 마찬가지이다. 이러한 문제점을 해결하기 위해 자바에서는 interface라는 것을 이용하여 이 문제를 해결하였다.

 

스프링에서도 마찬가지인데 이러한 문제를 해결하기 위해서 TV를 생성하는 공장을 만들어서, 이 공장의 getTV()등의 메소드를 이용하여 TV를 얻어올 수 있는 것이다. 이렇게 한다면 getTV("s) / getTV("L") 등의 메소드를 통해 TV객체를 얻어올 수 있고, 이러한 객체를 얻어오는 코드는 그 형식이 동일하게 유지된다. 이러한 이유로 우리는 IoC를 이용한다고 할 수 있고, Spring은 저런 TV공장과 같은 공장을 만들어주는 역할을 한다.

DI (Dependency Injection)

DI란 Dependency Injection의 약자로, 의존성 주입이라고 한다. 공장에서 만들어진 instance를 객체에 주입하여 사용하는 방법이다. DI는 클래스 사이의 의존 관계를 빈(Bean) 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것을 말한다.

 

DI없이 일반적인 클래스의 사용 방법은 다음과 같다.

위와 같이 자동차 클래스를 만들기 위해선, 먼저 자동차 클래스 안에서 엔진 클래스를 새로 생성해야 한다. 반면 DI를 적용한 코드는 다음과 같다.

위의 코드에서는 엔진변수 v5에 객체가 따로 할당되는 코드가 없다. 그러나 @Component, @Autowired 와 같은 어노테이션이라고 부르는 방법으로 IoC컨테이너가 객체들 간의 의존관계를 참고하여 자동으로 인스턴스를 주입하게 해준다. 이러한 방법이 바로 DI를 이용하는 방법이라고 할 수 있다.

Spring에서 제공하는 IoC/DI 컨테이너

  • BeanFactory : IoC/DI에 대한 기본 기능을 가지고 있다.
  • ApplicationContext : BeanFactory의 모든 기능을 포함하며, 일반적으로 BeanFactory보다 추천된다 트랜잭션처리, AOP등에 대한 처리를 할 수 있다. BeanPostProcessor, BeanFactoryPostProcessor등을 자동으로 등록하고, 국제화 처리, 어플리케이션 이벤트 등을 처리할 수 있다.
  • BeanPostPricessor : 컨테이너의 기본로직을 오버라이딩하여 인스턴스화와 의존성 처리 로직 등을 개발자가 원하는 대로 구현 할 수 있도록 한다.
  • BeanFactoryPostProcessor : 설정된 메타 데이터를 커스터마이징 할 수 있다.