Spring Boot 실무 가이드 · Part 3

빈과 의존성 주입

Spring의 실제 동작을 좌우하는 빈 등록과 주입 방식 이해하기

작성 기준2026년 7월버전과 지원 현황은 이후 달라질 수 있으니 공식 문서를 함께 확인하세요.

이 파트에서 다루는 내용

빈 등록 방법주입 방식 비교빈이 여러 개일 때스코프와 순환 참조
01

빈을 등록하는 방법은 크게 두 가지입니다

빈(Bean)은 Spring 컨테이너가 관리하는 객체입니다. 컨테이너가 만들고, 연결하고, 필요할 때 꺼내 씁니다. 등록 방법은 내가 작성한 클래스인지 아닌지로 갈립니다.

@Component 계열
내가 만든 클래스

클래스에 애노테이션을 붙이면 컴포넌트 스캔이 찾아서 등록합니다. 역할에 맞는 것을 골라 씁니다.

  • @Service: 비즈니스 로직
  • @Repository: 데이터 접근
  • @Controller / @RestController: 웹 요청 처리
  • @Component: 그 외 일반 컴포넌트
@Bean 메서드
외부 라이브러리 클래스

@Configuration 클래스 안의 메서드가 반환하는 객체를 빈으로 등록합니다. 소스를 수정할 수 없는 외부 클래스에 씁니다.

두 방식의 코드java
// 내가 만든 클래스: 애노테이션으로 등록
@Service
public class OrderService {
}

// 외부 라이브러리 클래스: @Bean 메서드로 등록
@Configuration
public class HttpConfig {

    @Bean
    public RestClient restClient() {
        return RestClient.builder()
                .baseUrl("https://api.example.com")
                .build();
    }
}

@Service 대신 @Component를 써도 동작은 같습니다. 다만 역할이 드러나는 애노테이션을 쓰면 코드를 읽는 사람이 계층을 바로 알 수 있습니다.

02

주입은 생성자로 받는 것이 원칙입니다

주입 방식은 생성자, 필드, setter 세 가지가 있습니다. 결론부터 말하면 생성자 주입을 기본으로 씁니다. 취향 문제가 아니라 이유가 분명합니다.

생성자 주입
권장
  • final로 선언할 수 있어 객체 생성 후 값이 바뀌지 않습니다
  • 의존성이 없으면 객체 생성 자체가 실패해 문제를 일찍 발견합니다
  • 테스트에서 new로 직접 만들 수 있어 컨테이너 없이 단위 테스트가 됩니다
  • 생성자 파라미터가 많아지면 클래스가 너무 많은 일을 한다는 신호가 됩니다
필드 주입
권장하지 않음
  • @Autowired를 필드에 직접 붙이는 방식입니다
  • final을 쓸 수 없어 값이 바뀔 수 있습니다
  • 컨테이너 없이 테스트하려면 리플렉션이 필요합니다
  • 의존성이 늘어나도 티가 나지 않아 클래스가 비대해집니다
setter 주입
제한적 사용

선택적 의존성이거나 실행 중 교체가 필요한 드문 경우에만 씁니다. 일반적인 서비스 클래스에는 쓰지 않습니다.

생성자 주입 작성법java
// 생성자가 하나면 @Autowired를 생략할 수 있습니다
@Service
public class OrderService {

    private final OrderRepository orderRepository;
    private final PaymentClient paymentClient;

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

// Lombok을 쓰면 final 필드 기준으로 생성자를 만들어 줍니다
@Service
@RequiredArgsConstructor
public class OrderService {

    private final OrderRepository orderRepository;
    private final PaymentClient paymentClient;
}

@RequiredArgsConstructor는 편하지만 팀에서 Lombok 사용 여부를 먼저 합의해야 합니다. 쓰지 않는 팀도 많습니다.

03

같은 타입 빈이 둘 이상이면 지정해 줘야 합니다

인터페이스 하나에 구현체가 여러 개일 때 Spring은 무엇을 넣을지 판단하지 못하고 기동에 실패합니다. NoUniqueBeanDefinitionException이 이 경우입니다.

@Primary
기본값 지정

여러 구현체 중 하나를 기본으로 정합니다. 대부분의 경우 이 구현을 쓴다는 의미입니다.

@Qualifier
이름으로 선택

주입받는 쪽에서 어떤 빈을 쓸지 이름으로 명시합니다. 상황에 따라 다른 구현을 써야 할 때 적합합니다.

목록으로 주입
전략 패턴

List나 Map으로 받으면 해당 타입 빈이 모두 들어옵니다. 결제 수단별 처리기처럼 여러 구현을 순회할 때 유용합니다.

구현체가 여러 개일 때java
public interface PaymentClient { }

@Component("cardPayment")
public class CardPaymentClient implements PaymentClient { }

@Component("pointPayment")
public class PointPaymentClient implements PaymentClient { }

// 1) 이름으로 지정
@Service
public class OrderService {
    private final PaymentClient paymentClient;

    public OrderService(@Qualifier("cardPayment") PaymentClient paymentClient) {
        this.paymentClient = paymentClient;
    }
}

// 2) 전부 주입받아 상황에 따라 선택
@Service
public class PaymentDispatcher {
    private final Map<String, PaymentClient> clients;

    public PaymentDispatcher(Map<String, PaymentClient> clients) {
        this.clients = clients;  // 빈 이름이 key로 들어옵니다
    }
}
04

스코프와 순환 참조

빈은 기본적으로 싱글톤입니다. 애플리케이션 전체에서 하나만 만들어 공유합니다. 그래서 빈에 요청별로 달라지는 상태를 필드로 두면 여러 요청이 같은 값을 건드리게 됩니다.

순환 참조는 A가 B를 주입받고 B가 다시 A를 주입받는 구조입니다. Spring Boot 2.6부터는 기본적으로 허용되지 않고 기동이 실패합니다.

싱글톤 주의
상태 공유

빈의 인스턴스 필드에 요청별 데이터를 저장하면 동시 요청에서 값이 섞입니다. 요청 데이터는 메서드 파라미터와 지역 변수로 다룹니다.

순환 참조 해결
설계로 푼다
  • 공통 로직을 제3의 클래스로 분리합니다
  • 책임이 잘못 나뉜 신호이므로 구조를 다시 봅니다
  • 설정으로 허용하는 우회는 마지막 수단입니다
prototype 스코프
드물게 사용

요청할 때마다 새 인스턴스를 만듭니다. 다만 싱글톤 빈이 prototype 빈을 주입받으면 처음 한 번만 생성되므로 의도대로 동작하지 않습니다.

실무 기준

순환 참조 오류를 만나면 우회 설정을 찾기 전에 클래스 책임을 먼저 의심해야 합니다. 대부분 두 서비스가 서로의 기능을 조금씩 필요로 하는 상태이고, 공통 부분을 분리하면 자연스럽게 풀립니다.

버전

3.x와 4.x 차이

본문은 현장에서 가장 많이 쓰는 3.x 기준입니다. 4.x에서 달라진 부분만 아래에 정리합니다.

  • Spring Boot 2.6부터 순환 참조가 기본 금지입니다. 3.x·4.x도 동일하며, spring.main.allow-circular-references로 되살릴 수 있지만 권장되지 않습니다.
  • 4.0은 JSpecify 기반 널 안정성 애노테이션을 포트폴리오 전반에 적용했습니다. 코틀린이나 정적 분석 도구를 함께 쓰면 널 관련 경고가 3.x보다 많이 잡힐 수 있습니다.
체크

이 파트 완료 기준