Post

Spring 의존성 주입, 제어의 역전

Spring 의존성 주입, 제어의 역전

스프링(Spring)의 핵심: 의존성 주입(DI)과 제어의 역전(IoC)

1. 왜 이 개념이 중요한가?

스프링 프레임워크는 결국 두 가지 원칙 위에 세워졌다.

  • 제어의 역전(IoC): 객체 생성, 생명주기 관리를 개발자가 아닌 프레임워크(SPRING)가 맡는다.
  • 의존성 주입(DI): 필요한 의존 객체를 직접 생성하지 않고 외부에서 주입받는다.

이 두 개념을 통해 결합도는 낮추고, 유지보수성과 테스트 용이성은 크게 높일 수 있다.


2. 제어의 역전(IoC: Inversion of Control)

✅ 기존 방식 (제어 직접 수행)

1
2
3
4
5
6
7
public class OrderService {
    private OrderRepository repo = new OrderRepository(); // 직접 생성

    public void order() {
        repo.save();
    }
}
  • 문제: OrderServiceOrderRepository 구체 구현에 강하게 결합됨
  • 테스트 시 OrderRepository를 바꾸기 어려움

✅ IoC 방식 (제어권 위임)

1
2
3
4
5
6
7
public class OrderService {
    private OrderRepository repo;

    public OrderService(OrderRepository repo) {
        this.repo = repo;
    }
}
  • OrderService는 더 이상 객체 생성을 직접 하지 않음
  • 외부에서 어떤 구현체를 넘길지 “제어의 주도권”이 바뀜 → IoC

3. 의존성 주입(DI: Dependency Injection)

의존성 주입은 IoC의 구현 방법 중 하나로, 필요한 객체를 외부에서 주입받는다.

1) 생성자 주입 (가장 권장됨)

1
2
3
4
5
6
7
8
9
@Component
public class OrderService {
    private final OrderRepository repo;

    @Autowired
    public OrderService(OrderRepository repo) {
        this.repo = repo;
    }
}

2) 필드 주입 (테스트 어렵고 비추천)

1
2
3
4
5
@Component
public class OrderService {
    @Autowired
    private OrderRepository repo;
}

3) 세터 주입 (선택적 의존성에 적합)

1
2
3
4
5
6
7
8
9
@Component
public class OrderService {
    private OrderRepository repo;

    @Autowired
    public void setRepo(OrderRepository repo) {
        this.repo = repo;
    }
}

4. Spring이 DI를 처리하는 방식

  • @Component로 등록한 클래스는 스프링이 **빈(Bean)**으로 관리
  • @Autowired를 통해 의존 객체를 찾아서 주입
  • ApplicationContext가 이 모든 과정을 자동 수행
1
2
3
4
5
6
7
8
@Configuration
@ComponentScan
public class AppConfig {}

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    OrderService service = ctx.getBean(OrderService.class);
}

5. 실무에서 이렇게 적용됨

✅ 예: MemberServiceMemberRepository를 사용

1
2
3
4
5
6
7
8
9
@Service
public class MemberService {
    private final MemberRepository repo;

    @Autowired
    public MemberService(MemberRepository repo) {
        this.repo = repo;
    }
}
  • MemberRepository가 JPA 구현이든, 메모리 저장소든 주입만 바꾸면 됨
  • 테스트에서도 가짜(Mock) 객체 주입 가능 → 단위 테스트 용이

6. 장점 정리

항목효과
IoC객체 생성 책임이 프레임워크로 이동 → 결합도 낮춤
DI필요한 구현체를 외부에서 주입 → 테스트, 확장성 용이
객체지향 원칙DIP(의존 역전), OCP(개방-폐쇄) 원칙 충족

7. 결론

Spring의 DI와 IoC는 단순히 문법이 아니라, 유지보수 가능한 구조를 만들기 위한 철학과 구조 설계 방식이다. 이 개념을 이해하고 쓰지 않으면 Spring은 그냥 무거운 컨테이너일 뿐이다. 핵심은 “내가 객체를 만들지 않는다”, **“필요한 건 외부에서 주입받는다”**는 두 가지 원칙이다.

This post is licensed under CC BY 4.0 by the author.