인생을 코딩하다.

[Spring] IOC와 DI 본문

Spring

[Spring] IOC와 DI

Hyung1 2021. 2. 9. 19:31
728x90
반응형

Spring 프레임워크는 자바 엔터프라이즈 애플리케이션을 개발하기 위한 프레임워크다
즉, 기업들에게 애플리케이션을 보다 쉽게 개발할 수 있도록 서비스를 제공한다

 

어떻게?

데이터베이스 연동이나 다른 시스템과의 연동같은 복잡한 로직을 분리시켜개발자가 비즈니스 로직 에만 신경쓰도록

만들어주는 핵심 기능이 IOC와 DI다.

 

IOC (Inversion of Control)

  • 제어의 역전
  • 개발자가 아닌 프로그램이 코드의 흐름을 제어하는 것
  • 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)이라 한다.
public class HyungIl{
  private Child child;

  public HyungIl(){
    this.child = new Hosick();
  }

  public void carry(){
    this.child.study();
  }
}

interface Child{
  void study();
}

class Hosick implements Child{
  @Override
  void study(){
    System.out.println("찡찡대기");
  }
}

class Hosick implements Child{
  @Override
  void study(){
    System.out.println("주말이니 쉬러가기");
  }
}

위 코드를 보면 Hyungil 클래스는 본인의 Child 필드를 Hosick  클래스로 결정하고 있다
이는 본인의 비즈니스 로직을 작성할 뿐만 아니라 아닌 필드의 인스턴스까지 결정과 생성하고 있음을 알 수 있다

 

이렇게 되면 무엇이 문제인가?

 

예를 들어

 

Hosick 클래스 생성자의 파라미터가 필요하게 되었다고 가정하자 ,그러면 Hyungil 클래스의 생성자도 바꾸어 주어야 한다. 만약 Hyungil 과 같은 클래스가 100개라고 생각해보자. 100개의 클래스를 모두 바꾸어야 한다. 이러한 사실들로 볼때 그 시스템은 클래스 간의 결합도가 높다. 따라서 이러한 결합도를 줄이고 SOLID의 SRP(Single Responsibility Principle즉, 단일 책임 원칙을 지키고자 나온 개념이 IOC 이다. IOC 개념은 Spring에서만 국한되지 않는다. IOC 는 제 3자에게 제어권을 주면서 자신의 비즈니스 로직에만 집중하는 개념이다. 따라서 위 예제를 고쳐보면

 

public class AppConfig{
  public Hyungil work(){
    return new Hyungil();
  }

  public Hosick smoke(){
    return new Hosick();
  }

  public Minsub gaepodong(){
    return new Minsub();
  }
}

public class Hyungil{
  private Child child;

  public Hyungil{
    this.child = new AppConfig().smoke();
  }

  //이하 동일
}

Hyungil 클래스의 child 필드의 인스턴스 생성을 AppConfig 클래스에 맡김으로써 만약 Hosick 클래스가 바뀌더라도 Hyungil 클래스는 신경을 안써도 된다. AppConfig 클래스같은 역할을 하는 클래스를 컨테이너라 부를 수 있다.

 

DI (Dependency Injection)

  • IOC를 구현하는 방법 중 하나

  • 의존성 주입

  • 클래스들간 의존관계를 설정한 정보를 토대로 컨테이너가 자동으로 연결하는 것

  • 지켜야할 조건

    1. 코드에 의존 관계가 드러나지 않는다. 그렇기 위해 인터페이스에 의존한다
    2. 의존관계는 제 3자에 의해 결정되어야 한다.
    3. 의존관계는 사용할 인스턴스의 참조는 제 3자로부터 받는다.
public class Hyungil{
  private Child child;

  public Hyungil(){
    this.child = new Hosick();
  }
}

interface Child{
  void study();
}

class Hosick implements Child{
  @Override
  void study(){
  }
}

앞서 나왔던 예제에서 Hyungil 클래스는 child 필드의 인스턴스를 Hosick 인스턴스로 결정하는 것이 보임으로써 DI가 적용이 안된 것을 알 수 있다.

 

public class Hyungil{
  private Child child;

  public Hyungil(Child child){
    this.child = child;
  }
}

제 3자로부터 child 필드의 인스턴스를 받아와서 적용하기 때문에 제 3자가 인스턴스를 결정하고 제공함을 알 수 있다.

Spring 에서는 Component 어노테이션을 붙여주면 Spring의 컨테이너가 알아서 인스턴스를 생성해주고 클래스 사이를 자동으로 연결해준다.때문에 Spring 컨테이너가 DI 개념의 제 3자 역할을 한다. 이렇게 Spring에서 관리하는 클래스들을 Spring에선 Bean 이라고 부르며 개발자가 설정한 이 Bean 들을 관리해주는 두 가지 컨테이너는

  • BeanFactory : IoC/DI 기본 기능
  • ApplicationContext : BeanFactory 모든 기능 포함, 일반적으로 추천

DI Container 를 사용함으로써 코드 작성 시 의존관계가 나타나지 않고, 결합도가 낮은 코드를 만들 수 있게 해준다.

따라서 변경과 확장을 자유롭게 할 수 있기 때문에 시스템이 유연해진다.

 

참고
[Spring] Spring의 정의와 기본 개념
Spring IoC/DI 컨테이너
[Spring] Spring의 핵심 기술 IoC/DI
IoC, DI란 무엇일까

 

728x90
반응형
Comments