
스프링의 핵심 철학은 IoC(Inversion of Control) 입니다. 이 철학을 구현하는 가장 대표적인 기술이 바로 의존성 주입(Dependency Injection) 입니다.
1. 의존성 주입이란?
의존성(Dependency): 객체가 다른 객체를 사용할 때, 이 관계를 ‘의존성’이라고 합니다.
주입(Injection): 필요한 의존 객체를 직접 생성하지 않고 외부에서 넣어주는 것입니다.
전통적인 방식 (의존 객체를 직접 생성)
public class OrderService {
private OrderRepository orderRepository = new OrderRepository(); // 직접 생성
}
DI 적용 방식 (외부에서 주입)
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) { // 생성자를 통해 주입
this.orderRepository = orderRepository;
}
}
2. 스프링에서 DI가 중요한 이유
구분 | 설명 |
유연성 | 구현체 변경이 쉬움 (ex: 메모리 DB → MySQL) |
테스트 용이성 | 가짜 객체(Mock)를 주입하여 단위 테스트 가능 |
결합도 감소 | 객체 간의 강한 결합을 피하고 느슨한 연결을 유지 |
SOLID 원칙 준수 | 특히 DIP(Dependency Inversion Principle)를 지킬 수 있음 |
3. 스프링에서 의존성 주입하는 방법 3가지
생성자 주입 (Constructor Injection) ⭐️ 가장 권장되는 방식
@Component
public class OrderService {
private final OrderRepository orderRepository;
@Autowired // 생략 가능 (생성자가 1개일 경우)
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
장점
- final 키워드로 불변 보장
- 주입받지 못하면 컴파일 시점에 에러 발생
- 테스트 시에도 명확한 의존성 요구
필드 주입 (Field Injection)
@Component
public class OrderService {
@Autowired
private OrderRepository orderRepository;
}
단점
- 테스트 시 주입 불가능 (Reflection 사용해야 함)
- DI 프레임워크가 없으면 객체 생성 자체가 안 됨
- 외부에서 변경 불가능 (private)
🚫 실무에서는 테스트/유지보수 측면에서 비권장 방식입니다.
세터 주입 (Setter Injection)
@Component
public class OrderService {
private OrderRepository orderRepository;
@Autowired
public void setOrderRepository(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
장점
- 선택적 의존성 주입에 적합
- DI 프레임워크 없이도 기본 생성자로 객체 생성 가능
❗ 단점
- 불변성 보장이 안 됨
- 의존성 누락 가능성이 있음
4. 컴포넌트 스캔과 빈 등록
자동 등록 (@Component 계열 사용)
@Component
public class OrderService {
...
}
- @Component 외에도 @Service, @Repository, @Controller 도 사용 가능
- @SpringBootApplication 아래 패키지부터 스캔
수동 등록 (@Configuration + @Bean)
@Configuration
public class AppConfig {
@Bean
public OrderService orderService() {
return new OrderService(orderRepository());
}
@Bean
public OrderRepository orderRepository() {
return new MemoryOrderRepository();
}
}
- 테스트나 특정 설정이 필요할 때 유용
- XML 없이 Java 코드로 구성 가능
5. 사용법
생성자 주입을 기본으로 사용
꼭 필요한 경우에만 필드/세터 주입 사용
@RequiredArgsConstructor를 사용하면 생성자 주입을 더 간편하게 구현 가능
@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository; // 생성자 자동 생성됨
}

주입 방식 | 장점 | 단점 | 권장 여부 |
생성자 주입 | 불변성, 명확한 의존성 | 코드가 약간 길어짐 | ✅ 매우 권장 |
필드 주입 | 코드 간단 | 테스트 어려움 | ❌ 비권장 |
세터 주입 | 선택적 의존성 | 불변성 보장 불가 | 🔸조건부 사용 |
'Back_End > Spring' 카테고리의 다른 글
Spring Boot(스프링부트) Bean 생명주기 관리 (1) | 2025.05.14 |
---|---|
스프링 @Bean, @Configuration, @Component 이란? (0) | 2025.03.31 |
스프링 @Controller와 @RestController의 차이점 (1) | 2025.03.28 |
비밀번호 해싱(Hashing) (1) | 2025.03.27 |
@Component와 @Configuration 비교 (1) | 2024.12.26 |