JAVA/Spring

DI(의존관계 주입, Dependency Injection)란 무엇인가?

min민 2024. 12. 20.

DI(의존관계 주입, Dependency Injection)란 무엇인가?

의존관계 주입(Dependency Injection, DI)은 객체 간의 의존성을 외부에서 주입받는 설계 방식을 말한다.
이 방식은 객체를 직접 생성하거나 내부에서 의존성을 설정하지 않고, 외부에서 필요한 의존성을 주입함으로써 결합도를 낮추고 코드의 유연성과 재사용성을 높인다.

 

 

 

 

 

DI의 핵심 개념

  1. 의존성(Dependency)
    • 한 객체가 다른 객체의 기능이나 데이터를 사용할 때, 해당 객체는 그 다른 객체에 의존한다고 말한다.
    • 예를 들어, OrderService가 PaymentService를 호출해 결제를 처리해야 한다면, OrderService는 PaymentService에 의존한다.
  2. 의존관계 주입(Dependency Injection)
    • 객체가 필요한 의존성을 스스로 생성하지 않고, 외부에서 주입받는 방식이다.
    • 이 과정은 보통 Spring Framework의 IoC 컨테이너에 의해 자동으로 처리된다.

 

 

 

 

DI의 주입 방법

Spring에서는 다음 세 가지 방법으로 의존성을 주입할 수 있다.

1. 필드 주입 (Field Injection)

필드에 직접 @Autowired를 붙여 의존성을 주입하는 방법이다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private PaymentService paymentService;

    public void processOrder(String orderId) {
        paymentService.processPayment(orderId);
    }
}

 

  • 장점: 간결하다.
  • 단점: 테스트 시 의존성을 직접 주입하기 어려우며, 객체 생성 시 의존성 설정이 명확하지 않다.

 

 

 

 

2. Setter 주입 (Setter Injection)

Setter 메서드를 통해 의존성을 주입하는 방법이다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private PaymentService paymentService;

    @Autowired
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processOrder(String orderId) {
        paymentService.processPayment(orderId);
    }
}

 

 

  • 장점: 선택적 의존성을 처리하기에 적합하다.
  • 단점: 객체가 생성된 이후에도 의존성을 변경할 수 있어 불변성을 보장하지 못한다.

 

 

 

3. 생성자 주입 (Constructor Injection)

생성자를 통해 의존성을 주입하는 방법이다. 가장 권장되는 방식이다.

import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final PaymentService paymentService;

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processOrder(String orderId) {
        paymentService.processPayment(orderId);
    }
}
  • 장점:
    • 불변성 보장: final 키워드를 사용해 주입된 의존성이 변경되지 않음을 명확히 할 수 있다.
    • 필수 의존성 명시: 생성자에 명시적으로 필요한 의존성을 선언할 수 있다.
    • 테스트 용이성: 의존성을 주입받는 객체를 쉽게 Mock 객체로 대체할 수 있다.

 

 

 

 

Spring에서 DI를 사용하는 이유

  1. 결합도 감소
    • DI는 객체 간 강한 결합을 제거하고, 인터페이스를 통해 의존성을 주입받아 결합도를 낮춘다.
  2. 코드 재사용성 증가
    • DI를 통해 객체가 독립적으로 설계되므로 다른 환경에서도 재사용이 가능하다.
  3. 테스트 용이성
    • 의존성을 외부에서 주입받기 때문에, 테스트 환경에서 Mock 객체를 쉽게 주입할 수 있다.

 

 

 

 

 

TIP: 기본적으로 알아야할 JAVA의 final 키워드

Java에서 final과 값 할당

Java에서 final 키워드는 변수의 값이 한 번만 할당될 수 있음을 보장한다.
즉, final 변수는 초기화 후 값이 변경될 수 없다. 이 속성은 **불변성(Immutability)**을 제공한다.

 

final 사용 시 값 할당 규칙

1. 즉시 초기화

final 변수는 선언과 동시에 값을 할당해야 한다.

public class FinalExample {

    private final String message = "Hello, Java!";

    public String getMessage() {
        return message;
    }
}

 

 

2. 생성자에서 초기화

클래스에 final 필드가 있을 경우, 모든 생성자에서 해당 필드에 값을 할당해야 한다.

public class FinalExample {

    private final String message;

    // 생성자를 통한 초기화
    public FinalExample(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

 

 

 

3. 초기화되지 않은 경우 컴파일 오류 발생

만약 final 필드에 값이 할당되지 않으면 컴파일 오류가 발생한다.

public class FinalExample {

    private final String message;

    public FinalExample() {
        // message 값을 초기화하지 않았으므로 컴파일 오류 발생
    }
}

 

 

4. final 필드는 변경 불가능

값이 한 번 할당된 후에는 수정이 불가능하다.

public class FinalExample {

    private final String message = "Hello, Java!";

    public void setMessage(String newMessage) {
        // 컴파일 오류: final 변수는 값을 변경할 수 없음
        // this.message = newMessage;
    }
}

 

final이 제공하는 이점

  1. 불변성 보장
    • 한 번 초기화된 값은 변경되지 않아, 안정성과 예측 가능성을 제공한다.
  2. 스레드 안전성
    • final 필드는 여러 스레드가 동시에 접근하더라도 값이 변경되지 않으므로 스레드 안전하다.
  3. 가독성 증가
    • final 키워드를 사용하면 해당 변수가 변경되지 않음을 명시적으로 알릴 수 있어 코드의 가독성이 높아진다.

 

 

DI의 총 정리 + final 키워드 정리

- DI는 Spring의 핵심 기능이며, 이를 효과적으로 활용하면 유연성과 재사용성이 높은 코드를 작성할 수 있다.

- 또한, final 키워드를 활용해 불변성을 보장함으로써 안정적인 객체 설계를 할 수 있다.

- 이 글을 읽게 될 독자는 Spring 프로젝트를 설계하면서 이 두 가지를 적극 활용하면 추가 학습에 큰 도움이 될 수도 있다(mins)

댓글