[Spring] IoC와 DI

2026. 2. 11. 20:42·spring, jpa

개요


IoC(Inversion of Control)과 DI(Dependency Injection)은 Spring에서 핵심이 되는 개념입니다. IoC는 객체의 생성과 생명주기 관리의 제어권을 개발자가 아닌 외부에 일임하는 것이고, DI는 객체가 포함하는 의존 객체를 직접 생성하지 않고 외부로부터 주입받는 방식을 의미합니다. 따라서 DI는 IoC를 구현하는 대표적인 방법이며 이에 대한 내용을 해당 글에서 정리해보겠습니다.

 

 

DI(Dependency Injection)


A라는 클래스가 B라는 클래스를 사용할 때, A는 B에 의존한다고 표현합니다. DI는 이때 A가 B를 직접 생성하는 것이 아니라, 외부에서 생성된 B를 주입받아 사용하는 것을 의미합니다. DI가 적용된 코드와 그렇지 않은 코드의 예시는 아래와 같습니다.

/**
* DI가 적용되지 않은 코드
* 
* OrderService가 PaymentService를 직접 생성
* 강한 결합 발생
* 테스트 어려움
*/
public class OrderService {

    private PaymentService paymentService = new PaymentService();

    public void order() {
        paymentService.pay();
    }
}
/**
* DI가 적용된 코드
* 
* PaymentService를 외부(Spring)가 생성
* 생성자를 통해 주입
* 결합도 감소
* 테스트 용이
*/
@Service
public class OrderService {

    private final PaymentService paymentService;

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

    public void order() {
        paymentService.pay();
    }
}

 

 

IoC(Inversion of Control)


IoC는 객체의 생성, 의존성 연결, 생명주기 관리의 제어권을 개발자가 아닌 외부에 일임하는 것을 의미합니다. 이때 이 외부를 IoC 컨테이너 라고 지칭하는데, Spring에서는 IoC 컨테이너의 구현체로 BeanFactory와 이를 확장한 Application Context가 존재합니다. Spring에서는 일반적으로 더 많은 기능을 제공하는 ApplicationContext를 기본 컨테이너로 사용합니다. 아래는 일반적인 DI와 IoC를 적용한 코드입니다. IoC를 적용한 코드를 보면, 의존성을 직접 주입하는 것이 아니라 ApplicationContext에서 담당하는 것을 알 수 있습니다.

/**
* 기존 방식
*/
PaymentService paymentService = new PaymentService();
OrderService orderService = new OrderService(paymentService);
/**
* Inversion of Control
* 
* 객체 생성 및 연결을 컨테이너가 수행
* 코드상에서는 가져와서 사용하는 것만을 명시
* 제어권이 역전되었기 때문에 IoC라고 지칭
*/
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService = context.getBean(OrderService.class);

 

 

DI와 IoC를 사용하는 이유


DI와 IoC를 사용하는 이유는 낮은 결합도, 테스트 용이, 확장성 등 다양한 부분에서 도움이 되기 때문입니다. 이를 조금 더 구체적으로 보면 "객체가 무엇을 할지"와 "어떻게/누가 만들어 연결할지"를 분리해서 변경에 강한 구조를 만들 수 있다는 것이 핵심입니다. 먼저, DI를 사용함으로써 낮은 결합도를 보장해 구현체의 변경이 쉬워집니다.

public interface PaymentService {
    void pay(int amount);
}

@Service
public class CardPaymentService implements PaymentService {
    @Override
    public void pay(int amount) {
        // 카드 결제 로직
    }
}

@Service
public class OrderService {
    private final PaymentService paymentService;

    // 여기서 결제 방식을 카드에서 계좌이체로 변경하더라도 PaymentService의 구현체만 바꾸면 됩니다.
    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void order(int amount) {
        paymentService.pay(amount);
    }
}

 

 

또한, Mock 객체를 이용해 빠른 단위 테스트가 가능합니다. DI가 없으면 OrderService는 PaymentService를 직접 생성해야하기 때문에 단위 테스트가 어려워집니다. DI를 사용한다면, 단위 테스트 시 원하는 Mock 객체를 주입해 빠르고 안정적인 테스트가 가능합니다. 

 

class FakePaymentService implements PaymentService {
    boolean called = false;

    @Override
    public void pay(int amount) {
        called = true;
    }
}

public class OrderServiceTest {
    @Test
    void 주문시_결제가_호출된다() {
        FakePaymentService fake = new FakePaymentService();
        OrderService orderService = new OrderService(fake);

        orderService.order(1000);

        assertTrue(fake.called);
    }
}​

 

다음으로, IoC를 사용하게 되면 확장성과 유지보수성에서 이득을 볼 수 있습니다. IoC 컨테이너가 객체 생성/연결을 담당하면, 새로운 구현체나 정책이 추가되어도 기존 코드를 크게 수정하지 않고 확장할 수 있습니다. 예를 들어, 아래와 같이 상황에 따라 결제 구현체를 분기하고 싶을 때, Spring에서는 Profile이나 Condition으로 쉽게 교체할 수 있습니다.

@Configuration
public class PaymentConfig {

    @Bean
    @Profile("prod")
    public PaymentService prodPaymentService() {
        return new CardPaymentService();
    }

    @Bean
    @Profile("test")
    public PaymentService testPaymentService() {
        return new FakePaymentService(); // 테스트 환경용
    }
}

 

저작자표시 (새창열림)
'spring, jpa' 카테고리의 다른 글
  • [Spring] 엑셀파일 다운로드 기능 구현
  • [Spring] nGrinder를 이용한 대용량 데이터 부하테스트
  • [JPA] JPA 지연로딩과 N+1 문제
  • [Spring] Spring AOP
Jisung Jung
Jisung Jung
Jisung Jung의 기술블로그
  • Jisung Jung
    Jisung Jung의 기술블로그
    Jisung Jung
  • 전체
    오늘
    어제
    • 분류 전체보기 (66)
      • spring, jpa (15)
      • java (7)
      • go (3)
      • kafka (3)
      • network (1)
      • algorithm (12)
      • data structure (3)
      • database, sql (7)
      • infra (6)
      • bootcamp (6)
      • git (3)
  • 블로그 메뉴

    • 홈
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
Jisung Jung
[Spring] IoC와 DI
상단으로

티스토리툴바