🍀 Spring

DI: Dependency Injection

제어의 역전

IoC: Inversion of Control

정의

필요한 객체를 외부에서 결정하여 연결시키는 것
(= 객체 의존관계를 외부에서 넣어주는 것)

목적 및 특징

애플리케이션 실행 시점(런타임)외부에서 실제 구현 객체 인스턴스를 생성하고 주입하여 실제 의존관계가 연결된다.

장점

  • 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.
  • 코드의 재사용성, 유연성이 높아진다
  • 객체간 결합도가 낮아진다
  • 유지보수가 쉬우며 테스트가 용이해진다
  • 확장성을 가진다

단점

  • 의존성 관계가 많아지면 관계가 잘 보이지 않는다.
  • 역제어 구조로 코드를 쉽게 이해하기 어렵다.
    • 코드 복잡도 상승
      • 가독성 감소
      • 코드 추적 불편
  • 외부에서 조작하기 어려워, 테스트가 어렵다.
  • 프레임워크에 대한 의존도 증가

예시

Spring Container: IoC Container

주입방식

정형화된 컨트롤러, 서비스, 리포지토리 같은 코드는 컴포넌트 스캔을 사용한다. 그리고 정형화 되지 않거나, 상황에 따라 구현 클래스를 변경해야 하면 설정을 통해 스프링 빈으로 등록한다.
@Autowired가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어준다.
  1. 필드 주입
  1. Setter 주입
  1. 생성자 주입(권장)
    1. 순환 의존성 확인: 필드 주입으로는 순환 의존성을 파악하기 어렵다. 생성자 주입을 하게 되면 서버 기동 시 순환 의존성을 가지는 요소들을 파악할 수 있게 에러메시지를 표시하면서 서버가 가동이 되지 않는다.
    2. 불변성: 필드 주입은 final을 선언할 수 없지만 생성자 주입은 final을 선언함으로써 객체가 변하지 않도록 방지해준다.
    3. 단일 책임 원칙 위반 확인 가능
  1. @RequiredArgsConstructor 어노테이션을 이용한 의존성 주입
    1. @RequiredArgsConstructor라는 어노테이션을 붙이면 final 필드나 @NonNull이 붙은 필드에 대해 생성자를 생성해 준다. 주로 의존성 주입의 편의성을 위해서 사용된다.
    2. 생성자가 오직 하나만 있고, 생성자의 파라미터 타입이 빈으로 등록 가능한 존재라면 이 빈은 @Autowired 어노테이션 없이도 의존성 주입이 가능하다.

질문

의존성 주입을 해야하는 이유

  • 테스트가 용이해진다
  • 코드 재사용율이 높아진다
  • 객체 간의 의존성을 줄이거나 없앨 수 있다
  • 객체 간의 별합도를 낮추면서 유연한 코드를 작성할 수 있다

@Autowired 필드 주입 VS @RequiredArgsConstructor final 주입 VS Setter 주입

@RequiredArgsConstructor final 주입

  • 한번 의존성 주입을 받은 객체는 프로그램이 끝날 때까지 변하지 않는 특징을 가지므로 불변성을 표시해주는 것이 좋기 때문 → 객체의 불변성(Immutability) 보장
  • final이 붙어있기 때문에 인스턴스가 생성될 때 1번만 참조되므로 코드 변이의 걱정은 사라진다.
  • 순환 참조가 일어날 시, Exception이 발생하여 컴파일 중에 에러가 발생한다. 이를 통해 Test 단계에서 순환 참조를 파악하여 수정할 수 있다.

@Autowired 필드 주입

  • 단일 책임의 원칙 위반 가능성
  • 코드 변이의 가능성
    • final 옵션을 사용할 수 없기에 코드가 변질될 가능성이 존재
  • 불확실한 참조
    • @Autowired는 타입(Type)이 같은 빈(Bean)이 발견되면 그냥 주입
    • Type의 다른 객체가 여러 개일 때 문제가 발생
    • 서로 다른 A타입의 객체가 2개 존재한다면 @Autowired는 Error

Setter 주입

  • public으로 열려있기 때문에 다른 곳에서 해당 메서드를 통해 주입이 가능
    • 즉, 호출하지 말아야 할 메서드를 호출하게 될 수도 있다.

생성자 주입 추천 이유

  • final 사용 가능
  • 불변
  • 순환 참조 방지