본문 바로가기

배운내용 정리

Spring IoC와 DI

1. IoC

2. DI

3. 제어의 역전

1. IoC

IoC(Inversion of Control)
컨테이너가 코드 대신 오브젝트의 제어권을 갖고 있어 IoC(제어의 역전)이라 한다.
예를 들어, 서블릿 클래스는 개발자가 만들지만, 그 서블릿의 메서드를 알맞게 호출하는 것은 WAS이다.
이렇게 개발자가 만든 어떤 클래스나 메소드를 다른 프로그램이 대신 실행해 주는 것을 제어의 역전이라고 한다.

  • IoC, DI는 객체지향의 SOLID 원칙 그리고 GoF 의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴이다.
  • 이 둘을 더 자세하게 구분해 보자면 IoC는 설계 원칙에 해당하고 DI는 디자인 패턴에 해당한다.

2. DI

DI(Dependency Injection)
DI는 의존성 주입이란 뜻을 가지고 있으며, Spring에서는 클래스 사이의 의존 관계를 빈(Bean) 설정 정보를 바탕으로 컨테이너가 자동으로 연결해 주는 것을 말한다.

 

2-1 필드에 직접 주입

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.food = new Chicken();
        consumer.eat();

        consumer.food = new Pizza();
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}
  • Food를 Consumer에 포함 시키고 Food에 필요한 객체를 주입받아 사용할 수 있다.

 

2-2 메서드를 통한 주입

public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public void setFood(Food food) {
        this.food = food;
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        consumer.setFood(new Chicken());
        consumer.eat();

        consumer.setFood(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}
  • set 메서드를 사용하여 필요한 객체를 주입받아 사용할 수 있다.

 

2-3 생성자를 통한 주입

public class Consumer {

    Food food;

    public Consumer(Food food) {
        this.food = food;
    }

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer(new Chicken());
        consumer.eat();

        consumer = new Consumer(new Pizza());
        consumer.eat();
    }
}

interface Food {
    void eat();
}

class Chicken implements Food{
    @Override
    public void eat() {
        System.out.println("치킨을 먹는다.");
    }
}

class Pizza implements Food{
    @Override
    public void eat() {
        System.out.println("피자를 먹는다.");
    }
}
  • 생성자를 사용하여 필요한 객체를 주입받아 사용할 수 있다.

 

3. 제어의 역전

  • 이전에는 Consumer가 직접 Food를 만들어 먹었기 때문에 새로운 Food를 만들려면 추가적인 요리준비(코드변경)가 불가피했다.
    • 그렇기 때문에 이때는 제어의 흐름이 Consumer → Food였다.
  • 이를 해결하기 위해 만들어진 Food를 Consumer에게 전달해 주는 식으로 변경함으로써 Consumer는 추가적인 요리준비(코드변경) 없이 어느 Food가 되었든지 전부 먹을 수 있게 되었다.
    • 결과적으로 제어의 흐름이 Food → Consumer로 역전되었다.

'배운내용 정리' 카테고리의 다른 글

Github Action CI/CD + Docker  (0) 2024.04.02
JDBC  (0) 2023.11.13
Spring MVC  (0) 2023.11.09
REST  (0) 2023.11.07
IntelliJ 한글깨짐 현상 수정  (0) 2023.11.04