Back-End/Spring Boot + Kotlin

Spring Boot 의존성 주입 (Dependency Injection)

김검정 2025. 4. 16. 16:31

의존성? 의존성이 뭘까?

어떤 물건을 만들거나 사용할 때 다른 것이 꼭 필요할때 우리는 그것을 의존한다고 한다.

예를 들어 자동차는 엔진이 꼭 필요하다.

  • 자동차는 혼자서는 움직일 수 없다.
  • 반드시 엔진이 있어야 움직일 수 있다.
  • 자동차는 엔진에 의존하고 있다고 말할 수 있다.

이처럼 어떤 객체가 다른 객체를 필요로 할 때, 의존성이 있다고 말한다.

 

그렇다면 의존성 주입(Dependency Injection) 이란 무엇일까?

 

만약 자동차가 엔진을 직접 만들 필요 없이, 공장에서 엔진을 가져와 조립할 수 있다면 더 편리하지 않을까?? 

>>> 이것이 의존성 주입니다.

 

쉽게 말해

  • 자동차(클래스)는 엔진을 직접 만들지 않음
  • 필요한 엔진을 공장에서(스프링)  가져옴
  • 스프링이 자동차에 엔진을 자동으로 넣어줌(의존성 주입)!

 

오호라..스프링이 있으면 편리해 보인다. 그럼 만약에 의존성 주입이 없다면 어떤 문제가 생길까???

class Car {
    private Engine engine = new Engine();  // 자동차가 직접 엔진을 생성
    
    public void start() {
        engine.run();
    }
}

 

이런 식으로 코드를 작성할 경우

  1. 자동차(Car)가 직접 엔진을 생성하고 있다.
  2. 나중에 엔진을 바꾸고 싶다면 자동차 코드를 직접 수정해야 한다.
  3. 코드가 유연하지 않고, 새로운 기능 추가도 어려워진다.

즉, 자동차가 직접 엔진을 만들게되면, 나중에 다른 엔진(전기 엔진, 하이브리드 엔진)으로 바꾸기 어려워진다.

 

 

그렇다면 의존성 주입을 사용하려면 어떻게 해야할까???

 

Spring Boot에서는 자동으로 필요한 객체(엔진)를 주입해줄 수 있다.

class Car {
    private Engine engine;

    public Car(Engine engine) {  // 외부에서 엔진을 넣어줌
        this.engine = engine;
    }

    public void start() {
        engine.run();
    }
}

 

이렇게 되면 자동차는 아주 쉽게 엔진을 교체할 수  있다.

  • Engine engine = new GasEngine();  (가솔린 엔진)
  • Engine engine = new ElectricEngine(); (전기 엔진)
  • Engine engine = new HybridEngine(); (하이브리드 엔진)

즉, 자동차 스스로 엔진을 직접 만들 필요 없이, 외부에서 받아서 사용할 수 있다.

 

 

너무 신기하다 근데 스프링은 어떻게 의존성을 주입하는 걸까?

 

스프링은 자동으로 필요한 객체를 찾아 주입(Injection) 해준다.

@Component
class Engine {
    public void run() {
        System.out.println("엔진이 가동됩니다.");
    }
}

@Component
class Car {
    private final Engine engine;

    @Autowired  // 스프링이 자동으로 Engine을 넣어줌!
    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.run();
    }
}

 

@Autowired를 사용하면 스프링이 알아서 엔진을 찾아서(Car에) 넣어준다.

이제 Car 객체를 만들 때 자동으로 Engine이 들어간다.

 

 

의존성 주입 3가지 방법

 

1. 생성자 주입(추천)

class Car {
    private final Engine engine;

    @Autowired
    public Car(Engine engine) {  // 생성자를 통해 의존성 주입
        this.engine = engine;
    }
}

 

장점 : 

  • 반드시 필요한 값이 주입된다 (final 사용 가능)
  • 테스트하기 쉽고 유지보수도 편리하다

 

2. 필드 주입(사용 지양)

class Car {
    @Autowired
    private Engine engine;  // 필드에 직접 주입
}

 

단점 : 

  • 필수값이 빠질 수 있다.
  • 테스트하기 어렵다
  • Spring Context 없이 사용할 수 없다.

 

3. Setter 주입

class Car {
    private Engine engine;

    @Autowired
    public void setEngine(Engine engine) {  // Setter를 통해 주입
        this.engine = engine;
    }
}

 

장점 : 필요할 때 객체를 바꿀 수 있다.

단점 : 의존성이 필수가 아닐 수도 있음(Setter를 호출하지 않으면 값이 없다)

 

 

 

의존성에 대해 알아보았는데 의존성 주입에 대해 요약하자면

 

중요한 이유 !

  1. 코드의 재사용성이 높아짐 -> Car 클래스를 수정하지 않고 다양한 Engine을 사용가능
  2. 유지보수가 쉬워짐 -> Engine을 변경할 때 Car 클래스를 수정할 필요가 없다.
  3. 테스트하기 쉬움 -> 테스트할 때 가자(Mock) 객체를 쉽게 주입할 수 있다.
  4. 스프링이 자동으로 객체를 관리 ->  개발자가 직접 객체를 만들 필요가 없다.