[Spring] 의존관계 자동 주입

2025. 2. 18. 06:24코딩 도구/백엔드 개발 (Backend Development)

반응형

스프링 의존관계 자동 주입

김영한님의 "스프링 핵심 원리 - 기본편"을 수강하고 정리했습니다. 

1. 의존관계 자동 주입이란?

스프링에서는 객체 간의 의존성을 자동으로 주입해 주는 기능을 제공한다. 이를 통해 개발자가 직접 객체를 생성하고 주입하는 번거로움을 줄일 수 있으며, 코드의 결합도를 낮춰 유지보수성을 향상시킬 수 있다.

2. 의존관계 주입 방법

1) 생성자 주입 (Constructor Injection)

가장 권장되는 방식으로, 불변성을 보장하며, 테스트가 용이하다.

@Component
public class OrderService {
    private final MemberRepository memberRepository;
    
    @Autowired
    public OrderService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

생성자 주입의 특징

  • final 키워드를 사용하여 불변 객체를 만들 수 있음
  • 의존성 주입이 필수적이므로 객체가 항상 유효한 상태로 유지됨
  • 테스트 용이: 생성자를 통해 주입하므로, 수동 주입이 가능하여 단위 테스트가 쉬워짐

TIP: 생성자가 하나만 존재하면 @Autowired를 생략해도 자동 주입이 동작한다.


2) 필드 주입 (Field Injection)

가장 간단한 방식이지만, 사용을 지양하는 방법

@Component
public class OrderService {
    @Autowired
    private MemberRepository memberRepository;
}

필드 주입의 문제점

  • 외부에서 주입할 방법이 없음 → 단위 테스트가 어려워짐
  • DI 프레임워크에 강하게 의존적 → 유지보수성 저하
  • final 키워드 사용 불가 → 불변성을 보장할 수 없음

필드 주입은 사용하지 않는 것이 좋으며, 특별한 경우(Spring Bean이 아닌 외부 라이브러리에서 주입할 때)만 고려할 것


3) 수정자(setter) 주입

선택적, 변경 가능한 의존성을 주입할 때 사용

@Component
public class OrderService {
    private MemberRepository memberRepository;
    
    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

수정자 주입의 특징

  • 선택적인 의존 관계에서 사용 가능 (의존성이 필수가 아닐 때)
  • 테스트 시 객체 변경 가능
  • 하지만 객체가 완전히 생성된 후 주입되므로, 일관성 유지가 어렵다

TIP: setter 주입을 사용할 때는 @Autowired(required = false)를 활용하면 선택적으로 주입할 수 있다.

3. 빈이 여러 개일 경우 해결 방법

의존성이 동일한 타입의 빈이 여러 개 있을 경우, 어떤 빈을 주입할지 명확하게 지정해야 한다.

1) @Qualifier 사용

특정 빈의 이름을 명시하여 주입하는 방법

@Component
public class OrderService {
    private final DiscountPolicy discountPolicy;
    
    @Autowired
    public OrderService(@Qualifier("rateDiscountPolicy") DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}

@Qualifier의 단점: 빈 이름을 직접 명시해야 하므로, 오타 등의 실수가 발생할 가능성이 있음


2) @Primary 사용

기본적으로 주입할 빈을 지정하는 방법

@Primary
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class OrderService {
    private final DiscountPolicy discountPolicy;
    
    @Autowired
    public OrderService(DiscountPolicy discountPolicy) {
        this.discountPolicy = discountPolicy;
    }
}
  • @Primary가 적용된 빈이 우선적으로 주입된다.
  • @Qualifier와 함께 사용할 수도 있음 (@Qualifier가 있으면 @Primary보다 우선됨)

4. 실무에서 중요한 내용

1) 생성자 주입을 우선적으로 고려할 것

  • final 키워드를 활용하여 불변성을 유지하고, 객체가 항상 유효한 상태를 보장할 수 있음
  • 테스트 코드 작성이 용이하며, 명확한 DI 구조를 유지할 수 있음

2) @Autowired의 다양한 활용법 익히기

  • 생성자가 하나면 @Autowired 생략 가능
  • @Autowired(required = false)로 선택적 의존성 주입 가능

3) 빈이 여러 개일 경우 해결 방법 숙지

  • @Qualifier를 사용하여 명확한 빈 선택 가능
  • @Primary를 활용하여 기본 빈 설정 가능
  • List<>, Map<>을 활용하면 모든 빈을 주입받아 처리 가능

5. 결론

스프링에서 의존관계 자동 주입은 유지보수성과 생산성을 높여주는 핵심 기능이다. 생성자 주입을 기본으로 사용하고, 특정 상황에서만 필드 주입이나 수정자 주입을 고려하는 것이 좋다. 또한, 빈이 여러 개일 경우 @Qualifier, @Primary 등의 애노테이션을 적절히 활용하여 주입 대상을 명확히 지정하는 것이 중요하다.

반응형