@Autowired 의 마법
전 차시 IoC 는 「발상」 까지. 「Spring 으로는 어떻게 코드를 짜는가?」 가 다음 단계.
전 차시 실습에서는 main 에서 직접 주입했지만 — Spring 은 이를 자동화합니다.
「Dependency Injection」 = 클래스가 필요한 부품을 외부에서 받아쓰는 패턴. IoC 의 가장 일반적인 구현.
@Service // ⭐ ① Bean 등록
public class OrderService {
@Autowired // ⭐ ② 자동 주입
private MessageSender sender;
public void order() {
sender.send("주문 완료");
}
}
👉 두 어노테이션이 「IoC + DI」 의 전부. 컨테이너가 알아서 처리.
| 어노테이션 | 의미적 자리 |
|---|---|
@Component | 일반 Bean (특별한 의미 없음) |
@Service | 비즈니스 로직 계층 |
@Repository | 데이터 접근 계층 |
@Controller | 웹 요청 진입점 |
👉 기능적으로는 모두 동일 — Spring 이 같은 일을 함. 의미적 표시일 뿐.
@Service
class OrderService {
@Autowired
private MessageSender sender;
}
👉 가장 간단한 방식. 학습 단계와 짧은 예제에 적합합니다.
다만 final 을 못 붙이고, 테스트 시 객체에 의존성을 끼워 넣기 어렵습니다.
@Service
class OrderService {
private final MessageSender sender;
@Autowired // 생성자가 1 개면 생략 가능
public OrderService(MessageSender sender) {
this.sender = sender;
}
}
👉 final 가능 / 테스트 쉬움 / 순환 참조를 컴파일 시 검출. 실무 표준.
@Service
class OrderService {
private MessageSender sender;
@Autowired
public void setSender(MessageSender sender) {
this.sender = sender;
}
}
👉 객체 생성 후에 의존성을 바꿀 수 있는 「가변」 주입. 잘 쓰지 않습니다 — 객체가 「설정 누락」 상태로 잠시 존재할 수 있기 때문.
| 방식 | 장점 | 단점 |
|---|---|---|
| 필드 | 코드 짧음 | final 불가, 테스트 어려움 |
| 생성자 ⭐ | final, 테스트 쉬움, 순환 참조 검출 | 생성자 길어질 수 있음 |
| setter | 가변 의존성 | 객체 생성 후 누락 가능 |
👉 실무 표준 = 생성자 주입. 학습용 = 필드 주입 OK.
// main 에서
MessageSender s
= new GmailSender();
OrderService svc
= new OrderService(s);
svc.order();
@Service
class OrderService {
@Autowired
MessageSender sender;
}
// 끝!
// @Service 빠뜨림
public class OrderService {
@Autowired
private MessageSender sender;
}
// 실행 시
NoSuchBeanDefinitionException: No qualifying bean of type 'OrderService'
👉 등록 어노테이션이 없으면 Bean 으로 안 만들어짐 → 다른 곳에서 주입 불가.
@Service public class GmailSender implements MessageSender { ... }
@Service public class KakaoSender implements MessageSender { ... }
@Service
public class OrderService {
@Autowired
private MessageSender sender; // 둘 중 어느 것?
}
"NoUniqueBeanDefinitionException: expected single matching bean but found 2"
해결: @Primary 또는 @Qualifier("gmailSender") 로 지정.
@Service
@Primary // 기본 Bean 으로 지정
public class GmailSender implements MessageSender { ... }
@Service("kakao")
public class KakaoSender implements MessageSender { ... }
// 주입 시 명시적으로
@Autowired
@Qualifier("kakao")
private MessageSender sender;
IoC 의 발상은 안다. 직접 main 에서 주입.
@Autowired 한 줄로 자동 주입. 등록 어노테이션 4 가지를 안다.