스프링 개발을 막 시작했거나, 실무 중 코드 리뷰를 하다 보면 @Autowired
를 사용할지, 생성자 주입을 쓸지 고민하는 경우가 많습니다. 둘 다 의존성 주입(Dependency Injection)을 위한 방식이지만, 설계와 유지보수 측면에서 큰 차이가 있습니다.
이 두 방식의 차이와 실제로 어떤 방식이 더 바람직한지, 실무에서 어떤 기준으로 선택해야 하는지를 정리해보겠습니다.
1. @Autowired 주입 방식
@Autowired
는 스프링이 지원하는 의존성 자동 주입 어노테이션입니다. 필드, 생성자, 세터 등 다양한 위치에 붙일 수 있고, Spring Container가 해당 타입의 빈을 찾아 주입해줍니다.
1-1. 필드 주입 (Field Injection)
@Component
public class OrderService {
@Autowired
private PaymentService paymentService;
...
}
- 장점: 코드가 간결하다
- 단점: 테스트, DI 프레임워크 외에서 인스턴스 생성이 어려움
- 단점: 불변성(inject 후 변경 불가) 보장이 안됨
- 단점: 순환 참조 발생 시 디버깅 어려움
실무에서는 거의 권장되지 않는 방식입니다. 테스트 코드에서 필드를 주입할 수 없고, 리플렉션 없이는 대체 불가능하기 때문입니다.
1-2. 생성자 주입과 비교 전, 세터 주입은?
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
세터 주입은 선택적 의존성에는 유용하지만, 필수 의존성에는 권장되지 않습니다. 코드 상으로 어떤 의존성이 꼭 필요한지 한눈에 파악하기 어렵기 때문입니다.
2. 생성자 주입 (Constructor Injection)
요즘 스프링 진영에서 가장 권장되는 의존성 주입 방식입니다. @Autowired
어노테이션 없이도 단일 생성자일 경우 자동 주입되며, 코드가 명시적이고 테스트도 용이합니다.
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
...
}
- 장점: 불변성 보장 (final)
- 장점: 명확한 의존성 표현
- 장점: 단위 테스트 용이 (Mock 객체 주입 가능)
- 장점: 순환 참조 발생 시 빠르게 감지 가능
스프링 4.3 이후, 생성자가 하나뿐이라면 @Autowired
없이도 자동으로 의존성을 주입합니다.
또한 final
키워드를 통해 의존성을 불변으로 선언할 수 있어, 설계 측면에서 안정성과 가독성을 모두 확보할 수 있습니다.
3. 비교 요약
구분 | 필드 주입 | 세터 주입 | 생성자 주입 |
---|---|---|---|
가시성 | 낮음 | 중간 | 높음 |
불변성 | 보장 안됨 | 보장 안됨 | 보장됨 (final) |
테스트 용이성 | 낮음 | 중간 | 높음 |
순환 참조 감지 | 어려움 | 중간 | 쉬움 |
권장 여부 | 지양 | 조건부 사용 | 권장 |
4. 실무 조언
- 필수 의존성은 반드시 생성자 주입을 사용하세요.
- 선택적 의존성(Optional)은 필요 시 세터 방식으로 처리할 수도 있습니다.
- 테스트 가능한 구조, 리팩토링에 유리한 설계를 위해 생성자 주입을 기본값으로 삼으세요.
이러한 기준을 팀 컨벤션으로 잡고 통일성 있게 관리하면, 코드 품질이 눈에 띄게 올라갑니다.
5. 생성자 주입이 정답에 가깝다
Spring이 지원하는 다양한 DI 방식 중에서 “생성자 주입”이 가장 명시적이고 안전한 방식입니다. 단순한 코드도 DI 방식을 달리하면 유지보수성에 큰 차이를 만들 수 있습니다.
지금이라도 @Autowired
를 생성자로 바꾸는 리팩토링을 시작해보세요. 테스트 코드가 편해지고, 코드가 더 이해하기 쉬워질 것입니다.
'개발 > JAVA' 카테고리의 다른 글
@Configuration과 @Bean의 차이 – Spring 개발자라면 반드시 짚고 가야 할 핵심 개념 (0) | 2025.09.23 |
---|---|
Spring Profile로 환경별 설정 관리하기 – 개발자라면 꼭 알아야 할 환경 분리 전략 (0) | 2025.09.22 |
@Component, @Service, @Repository 차이 – 스프링 개발자를 위한 실전 가이드 (0) | 2025.09.20 |
Spring Bean과 IoC/DI 개념 이해 – 스프링의 핵심 철학 (0) | 2025.09.19 |
@RestController vs @Controller – Spring MVC에서의 핵심 차이점 정리 (0) | 2025.09.18 |