섹션 8 : 의존관계 자동 주입
의존관계 주입의 4가지 방법
- 생성자 주입
- 수정자 주입(setter 주입)
- 필드 주입
- 일반 메서드 주입
생성자 주입
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
위의 코드처럼 생성자를 통해 의존관계를 주입 받는 경우이다.
- 생성자 호출시점에 딱 1번만 호출되어, 값을 세팅한 이후에는 변경할 수 없다.
- 불변, 필수 의존관계에 사용한다.
private final MemberRepository memberRepository;
private final로 선언된 경우, 반드시 값이 존재해야 한다.

discountPolicy처럼 값이 없을 경우에는 컴파일 오류가 발생한다.

위의 사진처럼 생성자가 딱 1개만 있는 경우, @Autowired를 생략해도 자동 주입 된다.
수정자 주입(Setter 주입)
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
System.out.println("memberRepository = " + memberRepository);
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
System.out.println("discountPolicy = " + discountPolicy);
this.discountPolicy = discountPolicy;
}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
System.out.println("1. OrderServiceImpl.OrderServiceImpl");
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입하는 방법이다.
- 스프링 빈이 등록된 이후에 연관 관계를 자동으로 주입한다.
- 스프링의 객체 생성 단계와 의존 관계 설정 단계가 분리되어 있다.
- 생성자 주입은 빈 등록시 의존 관계 주입이 이루어지고, 수정자는 두 번째 단계에서 주입된다.
- 선택, 변경 가능성 있는 의존관계에 적합하다.
@Autowired(required = false)
public void setMemberRepository(MemberRepository memberRepository) {
System.out.println("memberRepository = " + memberRepository);
this.memberRepository = memberRepository;
@Autowired의 기본 동작은 주입할 대상이 없으면 오류가 발생한다.
따라서 주입할 대상이 없어도 동작하게 하려면 @Autowired(required = false)로 지정하면 된다. (선택적)
필드 주입
@Autowired private MemberRepository memberRepository;
@Autowired private DiscountPolicy discountPolicy;
의존관계를 필드에 바로 넣어주는 것
코드도 간결해서 좋지만, 외부에서 변경이 불가능해서 테스트 하기가 매우 어렵다는 단점이 있다.

실제로 인텔리제이에서 권장하지 않는다는 경고가 뜬다.
스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 특별한 용도로 사용해야 한다 !
일반 메서드 주입
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
일반 메서드를 통해 주입받을 수 잇어서 한번에 여러 필드를 주입 받을 수 있다.
생성자 주입과 수정자 주입을 대부분 사용하기 때문에 일반적으로 잘 사용하지 않는다.
의존관계 자동 주입은 스프링 컨테이너가 관리하는 스프링 빈이어야 동작한다.
자동 주입 대상을 옵션으로 처리하는 방법
- @Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출이 안된다
- @Nullable : 자동주입할 대상이 없으면 null이 입력된다
- Optional<> : 자동 주입할 대상이 없으면 Optional.empty가 입력된다.
생성자 주입 - 최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자주입을 권장한다.
이유 1. 불변
의존관계 주입은 한 번 일어나면 대부분 애플리케이션 종료시점까지 의존관계를 변경할 일이 없다.
(대부분의 의존관계는 애플리케이션 종료 전까지 변하면 안된다.)
이유 2. 누락
생성자 주입을 사용하면 데이터를 누락했을 때 컴파일 시점에서 오류가 발생한다.
이때 필드에 final 키워드를 사용하면 값이 설정되는 오류를 컴파일 시점에 막아준다.

위 코드에서는 private final MemberRepository memberRepository;와 private final DiscountPolicy discountPolicy;
가 생성자를 통해 초기화되어야 한다.
하지만 현재 생성자 내부에서 해당 필드에 값을 할당하지 않아서 컴파일 오류(빨간 줄)가 발생한다.
final (상수)
- final 키워드를 사용하면 한 번 값이 할당된 후 변경할 수 없기 때문에, 객체의 상태를 불변으로 유지할 수 있다.
- 이는 예상치 못한 버그를 방지하는 데 도움이 된다.
lombok
@Component
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy){
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
기존의 코드
이전 시점보다 정말 많이 간결해지긴 했지만, lombok 라이브러리를 사용하면 다르다.
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
lombok 라이브러리에서 사용하는 @RequiredArgsConstroctor 기능을 사용하면 final이 붙은 필드를 모아서 생성자를 자동으로 만들어준다.
'Spring Study' 카테고리의 다른 글
[스프링 핵심 원리] - 기본편 #9 (1) | 2025.04.10 |
---|---|
[스프링 핵심 원리] - 기본편 #8 (0) | 2025.04.03 |
[스프링 핵심 원리] - 기본편 #6 (0) | 2025.04.02 |
[스프링 핵심 원리] - 기본편 #5 (1) | 2025.03.21 |
[스프링 핵심 원리] - 기본편 #4 (1) | 2025.03.14 |