Using @Autowired
Autowiring Collaborators
자동 주입은 @Autowired
어노테이션을 통해 수행됩니다. 스프링은 이 어노테이션이 붙은 필드나 생성자, Setter 메서드에 자동으로 의존성을 주입합니다.
자동 주입(Autowired)은 스프링 프레임워크에서 객체 간의 의존성을 자동으로 주입해 주는 기능으로, 개발자가 의존성을 수동으로 설정하지 않아도 스프링 컨테이너가 필요한 객체를 자동으로 찾아 주입해 줍니다. 스프링의 DI(Dependency Injection) 기능의 일환으로, 코드를 더 간결하게 작성할 수 있고, 객체 간의 결합도를 낮출 수 있습니다.
자동 주입 방식에는 필드 주입, Setter 주입, 생성자 주입이 있습니다.
@Autowired
어노테이션을 사용하여 의존성을 주입합니다.@Component
public class OrderService {
@Autowired
private PaymentService paymentService;
public void processOrder() {
paymentService.pay();
}
}
@Autowired
어노테이션을 사용하여 의존성을 주입합니다.@Component
public class OrderService {
private PaymentService paymentService;
@Autowired
public void setPaymentService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
paymentService.pay();
}
}
@Autowired
어노테이션을 사용하여 의존성을 주입합니다.@Autowired
어노테이션을 생략할 수 있습니다.@Component
public class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
paymentService.pay();
}
}
@Autowired
어노테이션을 사용하면, 스프링 컨테이너는 아래의 순서로 주입할 빈을 검색합니다.
@Qualifier
어노테이션을 함께 사용하여 주입할 빈을 명시할 수 있습니다.아래 예제는 같은 타입의 여러 빈 중에서 @Qualifier
를 사용하여 특정 빈을 주입하는 방법입니다.
@Component
public class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(@Qualifier("creditCardPaymentService") PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder() {
paymentService.pay();
}
}
@Component("creditCardPaymentService")
public class CreditCardPaymentService implements PaymentService {
// ...
}
@Component("paypalPaymentService")
public class PaypalPaymentService implements PaymentService {
// ...
}
@Qualifier
*를 사용하여 해결할 수 있습니다.NoSuchBeanDefinitionException
이 발생합니다.@Autowired(required = false)
로 설정하면, 빈이 존재하지 않을 때 주입을 생략할 수 있습니다.@Autowired(required = false)
private PaymentService paymentService;
Optional
을 활용하여 빈이 존재하지 않을 때 null
대신 빈값을 설정할 수 있습니다.@Autowired
private Optional<PaymentService> paymentService;
예시 코드:
package org.example.di04;
import org.springframework.beans.factory.annotation.Autowired;
public class WriteAction {
@Autowired
private BoardDAO dao; // 필드에 직접 주입
public WriteAction() {
System.out.println("Write Action 생성자");
}
public void getDAO() {
System.out.println("dao : " + dao); // Autowired 없으면 Null
}
}
출력 결과:
Write Action 생성자
dao : org.example.di04.BoardDAO@<hashcode>
예시 코드:
package org.example.di04;
import org.springframework.beans.factory.annotation.Autowired;
public class WriteAction {
private final BoardDAO dao;
// 생성자에 @Autowired 추가
@Autowired
public WriteAction(BoardDAO dao) {
System.out.println("WriteAction 생성자");
this.dao = dao;
}
public void getDAO() {
System.out.println("dao : " + dao);
}
}
BeanConfig:
@Bean
public WriteAction writeAction(BoardDAO dao) {
return new WriteAction(dao); // 생성자를 통해 주입
}
출력 결과:
WriteAction 생성자
dao : org.example.di04.BoardDAO@<hashcode>
예시 코드:
package org.example.di04;
import org.springframework.beans.factory.annotation.Autowired;
public class WriteAction {
private BoardDAO dao;
public WriteAction() {
System.out.println("Write Action 생성자");
}
// Setter 메서드에 @Autowired 추가
@Autowired
public void setDao(BoardDAO dao) {
System.out.println("setDao 호출");
this.dao = dao;
}
public void getDAO() {
System.out.println("dao : " + dao);
}
}
BeanConfig:
@Bean
public WriteAction writeAction() {
return new WriteAction(); // Setter로 의존성 주입
}
BoardDAO
객체가 주입됩니다.출력 결과:
Write Action 생성자
setDao 호출
dao : org.example.di04.BoardDAO@<hashcode>
주입 방식 | 장점 | 단점 |
---|---|---|
필드 주입 | 코드가 간결함. 테스트 외의 간단한 의존성 주입에 적합. | 테스트와 유지보수가 어려움. 의존성이 보이지 않으므로 디버깅 복잡. |
생성자 주입 | 필수 의존성을 강제 가능. 불변 객체에 적합. 단일 생성자의 경우 @Autowired 생략 가능. | 코드가 길어질 수 있음. 선택적 의존성 주입에는 부적합. |
Setter 주입 | 선택적 의존성에 적합. 테스트 시 Mock 객체 설정이 용이. | 필드가 명시적으로 초기화되지 않을 위험이 있음. 의존성을 강제하지 않음. |