IoC와 DI, 제대로 알고 쓰자

Minseo Lim·2025년 4월 22일

🧠 이 글을 쓰게 된 계기

이 글을 준비하게 된 계기는 다름 아닌 누군가의 질문에서 시작됐다…

??? : Hey, 너 자바 좀 잘해?
나 : …모르겠네 그래도 열심히 공부는 하고 있어
??? : 너 프로젝트에서 IoC, AOP, DI 적용한 사례 설명해봐.
나 : 아 그거~~?? 쉽지 ㅋㅋㅋ (막상 못 말함)

??? : 알았어 그러면 추상화, 상속, 다형성, 캡슐화 적용한 부분 얘기해봐
나 : 상속은 DTO에서 하기도 하고… 많이 하는건데 그냥…

이게 문제다. 이론을 안다고 생각하고 프로젝트를 만들다 보면
내 코드의 설계 방식이 어떤 개념을 채택하고 있는지조차 모른 채 만들기 쉽다.

그래서! 이번 기회에 개념 기강 한 번 제대로 잡고,
지금 진행 중인 Spring Boot 프로젝트에 어떻게 적용했는지도 같이 정리해보려 한다.


1️⃣ IoC란?

Inversion of Control, 제어의 역전

객체의 생성과 의존성 관리를 개발자가 아닌 프레임워크가 담당하는 것
객체 간 의존 관계를 스프링 컨테이너가 알아서 조율한다

📌 핵심
→ 내가 객체를 new해서 쓰는 게 아니라
→ Spring이 대신 생성하고 연결해줌


2️⃣ DI란?

Dependency Injection, 의존성 주입
→ IoC를 구현하는 방법 중 하나

•	객체가 필요한 의존 객체를 직접 생성하지 않고 외부에서 주입받음
•	스프링에서는 생성자 주입을 많이 사용함
@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

👆 UserService는 UserRepository에 의존하지만
직접 만들지 않고 스프링이 알아서 주입해준다.


3️⃣ ApplicationContext & Bean

💡 ApplicationContext란?

스프링의 IoC 컨테이너
애플리케이션 실행 시 빈(Bean)을 생성하고, 의존성 주입 등을 관리함

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);

💡 Bean이란?

스프링이 관리하는 객체

@Component, @Service, @Repository, @Controller 등을 사용하면 자동 등록됨
@Bean으로 수동 등록도 가능
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService(userRepository());
    }
}

4️⃣ 실제 프로젝트 코드 예시

// StoreController.java
@RestController
@RequestMapping("/stores")
public class StoreController {
    private final StoreService storeService;

    public StoreController(StoreService storeService) {
        this.storeService = storeService;
    }

    @GetMapping
    public List<Store> getAllStores() {
        return storeService.findAllStores();
    }
}
  • Controller → Service → Repository 구조로 계층화
  • 각각의 의존성은 모두 DI를 통해 주입됨
  • IoC 컨테이너가 모든 흐름을 관리함

5️⃣ DI의 장점

✅ 결합도 감소
→ 객체 간 관계가 느슨해져 확장과 변경이 쉬움

✅ 테스트 용이성
→ 의존 객체를 Mock으로 바꿔서 단위 테스트 가능

✅ 가독성 & 관리성 향상
→ 구성과 로직이 분리되어 코드가 명확해짐


✍️ 마무리

의존 관계를 명확히 표현하고 유지보수하기 쉬운 구조를 만드는 데
IoC와 DI는 필수적인 개념이다.

특히 Spring Boot는 이걸 너무나도 자연스럽고 편하게 해준다.

이론만 알고 넘어가기보단,지금 내가 짜고 있는 코드에 적용된 개념을 스스로 인지하고 있어야 진짜로 쓰는 의미가 있다는 걸 이번 글을 쓰면서 다시 느끼게 됐다.


📌 다음 글 예고: 객체 지향 프로그래밍의 4가지 특징! (완전 필수)

profile
프로덕트 엔지니어 임민서입니다.

0개의 댓글