Back-End/Spring

[Spring] 의존성 주입(DI)과 IoC 컨테이너의 개념

유자맛바나나 2021. 7. 16. 02:52

스프링 프레임워크의 기본이자 핵심 기능인 DI와 IoC Container를 배워보자

 

❑ DI(Dependency Injection)

주입할 의존성

 

public interface PowerUnit {
    void useSource();
}

public class GasolineEngine implements PowerUnit {
    @Override
    public void useSource() {}
}

public class ElectricMotor implements PowerUnit {
    @Override
    public void useSource() {}
}

 

1. 의존 클래스 내부 정의

# 의존 클래스 내부 정의: 의존 Class ElectricMotor를 Car가 내부에서 직접 정의
public class Car {
    private PowerUnit electricMotor = new ElectricMotor(); // Dependency
}
  • 위와 같이 의존 클래스 ElectricMotor를 내부에서 정의하면 의존 클래스를 변경하고자 할 때(예를 들어 GasolineEngine) Car 클래스를 수정할 수 밖에 없다. 즉, Client 코드에 변경점이 발생한다.

2. 의존 클래스 외부 주입(Dependency Injection)

# 의존 클래스 외부 주입: 의존 Class ElectricMotor를 setter를 활용해 외부에서 주입(Dependency Injection)
public class Car {
    private PowerUnit powerUnit; // Dependency
    
    public void setPowerUnit(PowerUnit powerUnit) {
        this.powerUnit = powerUnit; // 외부 주입(Injection)
    }
}

public class CarFactory {
    public void makeNewCar() {
        Car newCar = new Car();
        newCar.setPowerUnit(new ElectricMotor()); // new GasolineMotor로 교체해도 Car 클래스 변경점 X
    }
}
  • 반면 의존 클래스를 외부(CarFactory)에서 주입 받게 된다면 ElectricMotor/GasolineEngine 등 PowerUnit의 여러가지 구현 클래스를 바꿔가며 조립할 수 있다. 이렇듯 외부에서 의존성을 주입할 경우 Client 클래스(Car)의 변경점이 발생하지 않는다. 이를 객체간 결합도가 낮아졌다고 표현한다.
  • Spring 프레임워크에서는 주로 생성자 주입, 세터 주입, 필드 주입 등의 방법으로 의존성을 주입한다.

 

3. DI의 장점

  • 프로그램은 여러 객체를 '조립'해서 만들게 된다. DI는 객체들을 조립해주는 것을 의미하고, Spring이 쉽고 편리하게 조립(=의존성을 주입)하는 기능을 제공하기 때문에 강력한 것이다.
  • DI를 사용하면 의존성을 쉽게 교체할 수 있으므로, 코드의 유연성이 향상된다. 예를 들어, 개발 및 테스트 환경에서 다른 구현이 필요한 경우, DI를 사용하여 쉽게 변경할 수 있다.
  • DI를 사용하면 의존성을 주입할 수 있으므로, 단위 테스트 시에 가짜 객체(Mock Object)나 스텁(Stub)을 쉽게 주입하여 테스트를 수행할 수 있다. 이를 통해 테스트 작성과 유지 관리가 용이해진다.

 

 

 

 IoC(Inversion Of Control) 컨테이너의 개념

Spring은 여러 객체를 '생성'해서 '조립'하는 것을 도와준다. 그리고 생성해서 조립한 결과물을 담을 그릇이 필요한데 이를 컨테이너라 부르고, Spring에서는 IoC 컨테이너라 한다.

 

IoC(Inversion Of Control) 컨테이너란

1.1. Introduction to the Spring IoC Container and Beans

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

-출처: Spring Framework Document

주요 내용을 직역하자면,

  • IoC는 DI로도 알려져 있으며, 서로 함께 작동되는(work with) 객체들간 의존성(dependencies)을 정의하는 과정이다.
  • 컨테이너는 빈(Bean)을 생성할 때 의존성을 주입하게 된다.
  • 그리고 이 과정은 근본적으로 bean 자체가 의존 객체를 만들어내는 것(Instantiation)의 역순(Inversion)이다.

세번째 내용이 이해하기 다소 어렵다. 좀 더 풀어 설명하자면

  1. Bean A → Bean B와 같이 의존관계를 가질 때(A controlling B)
  2. 코드 상으로는 A 클래스가 생성된 뒤 내부에서 B 인스턴스를 생성하게 되는데(=A가 의존 객체 B를 만들어내는 것),
  3. IoC 컨테이너에서는 B를 먼저 만들어 A에 넣어준다는 뜻이다.
  4. 따라서 B→A 역순으로 과정이 진행되어 Inversion Of Control 이라고 부르는 것.

의존관계가 있는 Bean들을 조립한 결과를 담은 것을 IoC 컨테이너라고 이해할 수 있다.

org.springframework.beans org.springframework.context packages가 IoC 컨테이너의 기본적인 패키지이다.

 

 

Reference

Spring 공식 문서 | https://docs.spring.io/spring-framework/docs/5.2.19.RELEASE/spring-framework-reference/core.html#spring-core