객체지향 프로그래밍에서 애플리케이션 간의 결합도를 낮추고, 확장성과 재사용성을 높이기 위한 중요한 개념이 DI(Dependency Injection)와 IoC(Inversion of Control)입니다. 스프링 프레임워크는 이 두 가지 원칙을 기반으로 동작하여, 개발자가 보다 깔끔하고 효율적인 코드를 작성할 수 있도록 도와줍니다.
1. Inversion of Control (IoC)
제어의 역전을 의미
- 스프링에서는 전통적인 방식에서는 Java 객체를 `new`로 생성하여 개발자가 관리하는 것이 아닌 , `Ioc 컨테이너`가 객체의 생성과 의존성 관리를 대신해줍니다.
IoC의 장점
- 낮은 결합도: 객체 간의 직접적인 의존성을 줄여, 한 객체의 변경이 다른 객체에 미치는 영향을 최소화합니다.
- 확장성과 유연성: 애플리케이션의 구성 요소들이 독립적으로 관리되므로, 새로운 기능 추가나 변경이 용이합니다.
- 테스트 용이성: 외부에서 의존성을 주입받기 때문에, 모의 객체(Mock)를 사용한 단위 테스트가 간편해집니다.
2. Dependency Injection (DI)
객체가 필요로 하는 의존성을 외부에서 주입받는 방식
- 즉, 객체 내부에서 직접 의존성을 생성하는 것이 아니라, 컨테이너가 생성한 객체를 주입받아 사용합니다.
DI의 주요 방식
생성자 주입(Constructor Injection) (그냥 이거 쓰면됨)
- 생성자를 통해 의존성을 주입받는 방식. 필수 의존성을 명시적으로 설정할 수 있어, 가장 안전한 방식입니다.
- 필수 의존성을 명확히 설정 가능
- 불변성 보장(`final` 사용 가능)
- 순환 참조 문제 예방 가능
@Service
public class UserService {
private final UserRepository userRepository;
// 생성자 주입을 통해 의존성을 주입받음
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
세터 주입(Setter Injection)
- 세터 메서드를 통해 의존성을 주입받는 방식. 선택적 의존성에 유용합니다.
- 선택적 의존성 주입 가능
- 필요에 따라 다른 객체로 변경 가능
- 객체 변경 가능성이 있어 유지보수가 어려울 수 있음
@Service
public class UserService {
private final UserRepository userRepository;
// 생성자 주입을 통해 의존성을 주입받음
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
필드 주입(Field Injection) (비추)
- 애노테이션(`@Autowired`)을 필드에 직접 적용하여 주입받는 방식.
- 코드가 간결하지만 테스트가 어려움(Mock 객체 주입이 어렵기 때문)
- 의존 관계가 명확하지 않음
- 순환 참조 문제 발생 가능
@Component
public class OrderService {
@Autowired
private OrderRepository orderRepository;
}
DI의 장점
- 유연한 코드 구성: 의존성이 외부에서 주입되므로, 객체들이 서로 강하게 결합되지 않습니다.
- 단위 테스트 용이: 실제 구현체 대신 `Mock 객체`를 주입해 테스트할 수 있어, 테스트가 간편해집니다.
- 재사용성과 확장성: 새로운 구현체를 추가해도 클라이언트 코드는 변경하지 않고, DI 컨테이너 설정만 바꾸면 됩니다.
3. IoC 컨테이너
애플리케이션이 실행될 때 객체(빈, Bean)를 생성 및 관리하며, 필요할 때 적절한 객체를 주입하는 역할
- 스프링의 IoC 컨테이너는 애플리케이션 구동 시 XML, 자바 기반 설정(`@Configuration`), 또는 애노테이션(`@Component`, `@Service` 등)을 읽어 객체를 생성하고 관리합니다.
- 컨테이너는 객체들의 생명 주기를 관리하며, 의존성 주입(DI)을 통해 객체 간의 관계를 설정합니다
IoC 컨테이너의 주요 기능
- 객체 생성 및 관리 (Bean 생성)
- 의존성 자동 주입 (DI 적용)
- 빈 라이프사이클 관리 (생성 → 사용 → 소멸)
- AOP 적용 가능 (공통 관심사 적용)
IoC 컨테이너 종류
IoC 컨테이너 | 설명 |
BeanFactory | 가장 단순한 IoC 컨테이너 (Lazy Loading) |
ApplicationContext | BeanFactory의 확장 버전 (Eager Loading) |
일반적으로 스프링에서는 ApplicationContext를 사용합니다.
4. 정리
개념 | 설명 |
IoC (제어의 역전) | 객체의 생성 및 제어를 개발자가 아닌 IOC 컨테이너가 담당 |
DI (의존성 주입) | 객체가 필요한 의존성을 직접 생성하지 않고, 외부에서 주입받는 방식 |
IoC 컨테이너 | 빈(Bean)을 생성, 관리, 주입하는 스프링의 핵심 컴포넌트 |
스프링의 IoC 컨테이너는 객체를 생성하고, DI를 통해 자동으로 주입하여 결합도를 낮추고 유지보수성을 향상시킬수 있다!
'BackEnd' 카테고리의 다른 글
계층적 캐싱(Caffeine + Redis)을 도입하여 쿠폰 발급 시스템 성능 최적화하기 (0) | 2025.03.20 |
---|---|
Redis Lua Script를 활용한 쿠폰발급 동시성 제어 및 성능 개선기 (0) | 2025.03.19 |
트래픽을 고려한 쿠폰 발급 서버 아키텍처 개선기 (0) | 2025.03.17 |
Spring 비동기 프로그래밍(@Async)과 ThreadPool 이해 (0) | 2025.03.09 |
스프링에서 SOLID 원칙 알아보기 (0) | 2025.03.06 |