테크레터

테크레터 1편. IoC와 DI가 뭔가요?

chandlerxx 2023. 12. 9. 01:21

안녕하세요. 

IoC와 DI는 스프링 프레임워크를 이해하기 위해 꼭 필요한 개념이라고 생각해요. 간단하게 짚고 넘어갈게요.

 

 

 

1. IoC(Inversion of Control) 


흔히 제어의 역전이라고 말하며, 보다 정확한 표현으로는 프로그램의 제어 흐름을 직접 제어하는 것보다 외부에서 관리되게 해야한다 입니다.

 

스프링에도 그 뜻이 담겨있습니다. 

  • 프레임워크 : 실행을 포함한 전체적인 흐름을 직접 제어하고, 개발자는 필요한 코드를 작성합니다.
  • 라이브러리 : 개발자가 필요한 코드를 호출해가며 프로그램의 전체 흐름을 직접 제어합니다. 

스프링 프레임워크는 IoC을 지원하도록 개발되었습니다. 필요에 따라 스프링에서 개발자의 코드를 호출해서 사용하며 전체적인 흐름을 관리합니다. (개발자 입장에서는 외부에서 관리되는 것처럼 느껴짐)

 

IoC의 바탕이 되는 개념이 다음으로 설명드릴 DI입니다.

 

 

2.  DI(Dependency Injection)


의존관계를 외부에서 결정(주입)해주는 것을 의미합니다. 핵심은 "동적인 객체 인스턴스 의존관계를 쉽게 변경"할 수 있다는 것입니다.

 

코드로 이해해보겠습니다.

예를 들어 올리브영에서 시즌별로 아이템 판매 정책을 다르게 시행한다고 가정해봅시다.

 

public interface ItemPromotions { // interface

}


// 아래는 구현체
public class SpringSeasonItem implements ItemPromotions {  
    // 봄 한정 프로모션
}

public class SummerSeasonItem implements ItemPromotions {
    // 여름 한정 프로모션
}

public class AutumnSeasonItem implements ItemPromotions {
    // 가을 한정 프로모션
}

public  class WinterSeasonItem implements ItemPromotions {
    // 겨울 한정 프로모션
}

 

public class Store {

    private ItemPromotions itemPromotions; // interface

    public Store() {
        itemPromotions = new SpringSeasonItem(); // implement
    }
}

 

우선 문제 발생 가능성이 높은 코드입니다.

 

첫째. 유연성이 떨어집니다.

ㄴstore입장에서는 시즌마다 코드를 변경해야 합니다.

 

둘째. 객체 지향의 5가지 원칙 중 하나인 DIP 원칙 위배

ㄴ 추상화(인터페이스)에만 의존해야하며 구현체에 의존해서는 안된다.

 

 

 

DI(의존관계 주입)를 이용해 위의 문제점을 해결할 수 있습니다.

아래 코드는 오직 인터페이스에만 의존하며 시즌별 프로모션에 대한 구현객체를 주입 받도록 변경하였습니다.

public class Store {

    private ItemPromotions itemPromotions; // interface

    public Store(ItemPromotions itemPromotions) {
        this.itemPromotions = itemPromotions; // interface
    }
}

 

스프링 DI 컨테이너가 런타임(애플리케이션 실행시점)에 외부에서 필요한 객체를 생성하여 클라이언트인 store에 전달할 것입니다. 동작은 아래와 같습니다. 

public class AppConfig { // 외부에서 객체를 생성하여 의존관계 주입해주는 역할

    public ItemPromotions itemPromotions() {
        return new SpringSeasonItem();
//        return new SummerSeasonItem();
//        return new AutumnSeasonItem();
//        return new WinterSeasonItem();
    }

 

이렇게 설계를 하면 클라이언트코드(Store클래스) 변경없이 동적인 객체 인스턴스 의존관계를 쉽게 변경 가능 합니다.

나중에 여름시즌이 다가오면 AppConfig에서 여름을 enable 처리하고, 나머지는 disable처리만 해주면 되겠네요.

 

 

3. 다음 이야기는 스프링 컨테이너


위의 예시는 AppConfig 사용해서 객체를 생성하여 의존관계 주입을 했습니다.

1. DIP 원칙을 준수하면서

2. 유연성을 높이는(확장에 열려있는 = OCP원칙 준수) 방향으로요.

 

앞으로는 스프링 컨테이너에 객체를 스프링 빈으로 등록하고, 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 할겁니다. (많이 사용하시는 애노테이션 세계ㅎㅎ)

 

 


[출처]