[스프링 로드맵] B-3. DI/Bean 실전 - @Autowired, @Qualifier, Profile

2026. 1. 19. 17:17·백엔드

이번 글은 “원리 설명”이 아니라, 실제 코드에서 반드시 부딪히는 상황들을 정리한다.

이 글의 목표

→ DI가 왜 필요하냐가 아니라, DI 쓰다 보면 생기는 문제를 어떻게 해결하냐


1. @Autowired는 핵심이 아니다

  • DI의 핵심은 @Autowired가 아님
  • 핵심은 “객체를 내가 만들지 않는다”
  • @Autowired는 주입 방법 중 하나

1-1) 왜 요즘은 @Autowired를 잘 안 쓰나?

과거 코드:

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;
}

요즘 권장 방식:

@Service
public class OrderService {

    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
}

차이의 핵심

  • 생성자 주입
    • 객체가 생성될 때 필수 의존성이 명확
    • 테스트 코드 작성 쉬움
    • 불변(final) 유지 가능
  • 필드 주입(@Autowired)
    • 테스트 어려움
    • 의존성 숨김
    • 런타임까지 오류가 안 보일 수 있음

그래서 요즘 정석은: 생성자 주입 기본, @Autowired는 거의 안 씀

(스프링 4.3 이후엔 생성자 하나면 @Autowired도 필요 없음)


2. 같은 타입 빈이 2개면 무조건 터진다

상황 예시: 구현체를 교체해야 할 때

  • 개발 초반: 메모리
  • 이후: JPA
  • 또는 테스트/운영 분리

이 순간 같은 타입(UserRepository) 빈이 2개가 된다.

@Repository
class MemoryUserRepository implements UserRepository { }

@Repository
class JpaUserRepository implements UserRepository { }

그리고 서비스에서:

@Service
class UserService {
    public UserService(UserRepository userRepository) { }
}

이 상태로 실행하면?

👉 실행 자체가 안 됨

NoUniqueBeanDefinitionException:
expected single matching bean but found 2

스프링 입장에선 당연하다. → “UserRepository 타입 빈이 2개인데 뭘 넣으라는 거지?”


3. 해결책 1: @Qualifier (이름으로 지정)

가장 직관적인 방법

@Service
class UserService {

    public UserService(
        @Qualifier("jpaUserRepository") UserRepository userRepository
    ) {
        this.userRepository = userRepository;
    }
}
  • @Qualifier는 빈 이름으로 지정
  • 빈 이름 기본값 = 클래스명 camelCase

장점 / 단점

  • 장점: 명확함
  • 단점: 이름 문자열에 의존 → 리팩토링에 약함

4. 해결책 2: @Primary (기본값 지정)

기본으로 선택될 빈을 하나 정함

@Repository
@Primary
class JpaUserRepository implements UserRepository { }

이제 서비스에서는:

@Service
class UserService {
    public UserService(UserRepository userRepository) { }
}

👉 자동으로 @Primary 붙은 빈이 주입됨

 

언제 쓰나?

  • “대부분 이 구현체를 쓰고, 가끔만 다른 걸 쓸 때”
  • JPA 구현이 기본, 테스트용/대체 구현이 보조일 때

5. @Qualifier vs @Primary 정리

상황 추천
특정 빈을 정확히 지정 @Qualifier
기본 구현체 하나 정하기 @Primary
구조 단순 @Primary
전략이 명확 @Qualifier

6. 환경에 따라 빈을 바꾸고 싶을 때: @Profile

대표적인 요구

  • 로컬: 메모리 저장소
  • 운영: JPA + 실제 DB
  • 테스트: Fake 구현체

예시

@Repository
@Profile("local")
class MemoryUserRepository implements UserRepository { }

@Repository
@Profile("prod")
class JpaUserRepository implements UserRepository { }

그리고 실행 시:

-Dspring.profiles.active=local

또는 application.yml:

spring:
  profiles:
    active: prod

결과

  • local → 메모리 저장소 빈만 등록
  • prod → JPA 저장소 빈만 등록

👉 같은 코드, 다른 환경


7. @Profile이 왜 중요한가?

  • if/else로 환경 분기 ❌
  • 코드 수정해서 환경 바꾸기 ❌
  • 빈 조합 자체를 환경별로 다르게 구성 ⭕

즉, 환경 차이를 “설정”으로 흡수하는 게 스프링 방식


8. 자주 헷갈리는거 정리

Q. @Autowired 꼭 알아야 하나?

→ 이름은 알아야 함, 하지만 핵심은 생성자 주입

Q. @Qualifier 남발해도 되나?

→ 보통은 @Primary + 일부만 @Qualifier

Q. @Profile은 언제 쓰는 게 맞나?

→ DB, 외부 API, 저장소 구현체처럼

환경마다 달라지는 빈


9. 요약

스프링에서는 생성자 주입을 기본으로 DI를 구성하고, 같은 타입의 빈이 여러 개일 경우 @Primary나 @Qualifier로 주입 대상을 결정한다. 또한 @Profile을 사용해 실행 환경별로 서로 다른 빈 구성을 선택할 수 있다.

'백엔드' 카테고리의 다른 글

[스프링 로드맵] C-2. 엔티티 설계 - @Entity와 기본 생성자의 의미  (0) 2026.01.19
[스프링 로드맵] C-1. JPA 큰 그림 - JPA vs Hibernate vs Spring Data JPA  (0) 2026.01.19
[스프링 로드맵] B-2. DI/Bean 내부 - 빈 등록 방식과 라이프사이클  (1) 2026.01.19
[스프링 로드맵] B-1. DI/Bean 기본 - new 지옥에서 벗어나기  (1) 2026.01.19
[스프링 로드맵] A-2. REST 확장 - POST/PUT/DELETE와 ResponseEntity  (0) 2026.01.19
'백엔드' 카테고리의 다른 글
  • [스프링 로드맵] C-2. 엔티티 설계 - @Entity와 기본 생성자의 의미
  • [스프링 로드맵] C-1. JPA 큰 그림 - JPA vs Hibernate vs Spring Data JPA
  • [스프링 로드맵] B-2. DI/Bean 내부 - 빈 등록 방식과 라이프사이클
  • [스프링 로드맵] B-1. DI/Bean 기본 - new 지옥에서 벗어나기
samsam031
samsam031
samsam031 님의 블로그 입니다.
  • samsam031
    samsam031 님의 블로그
    samsam031
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 디지털포렌식
      • 드림핵 문제풀이
      • 대외활동
      • 개발 실습
      • 컴퓨터 보안
      • 클라우드
      • 자격증
      • 자연어처리
      • 백엔드
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
samsam031
[스프링 로드맵] B-3. DI/Bean 실전 - @Autowired, @Qualifier, Profile
상단으로

티스토리툴바