/개발/Spring Boot 기동 실패 UnsatisfiedDependencyException 원인 6가지 해결법
DevelopmentSpring BootUnsatisfiedDependencyException

Spring Boot 기동 실패 UnsatisfiedDependencyException 원인 6가지 해결법

This article is not yet available in English. Showing the original Korean version.

Spring Boot가 UnsatisfiedDependencyException, No qualifying bean of type 오류로 기동조차 안 될 때 스택트레이스를 거꾸로 읽어 6가지 원인을 5분에 특정하는 진단법과 복붙 수정 코드를 정리했습니다.

Spring Boot 기동 실패 UnsatisfiedDependencyException 원인 6가지 해결법

Spring Boot 기동 실패! UnsatisfiedDependencyException 원인 6가지 5분 진단

어제까지 잘 뜨던 앱이 오늘 아침 빨간 스택트레이스 200줄과 함께 죽었습니다. Error creating bean with name ..., No qualifying bean of type ... available. 화면 가득한 nested exception을 보면 심장이 철렁하지만, 결론부터 말씀드리면 당황하지 말고 맨 아래 한 줄부터 읽으면 됩니다.

이 글은 JWT 인증 실패나 Whitelabel 404 같은 '떠 있는 앱의 런타임 에러'가 아니라, 애플리케이션이 기동 자체에 실패하는 빈(Bean) 등록·주입 단계 문제에 한정해 다룹니다. 이 단계의 실패 패턴은 사실상 6가지뿐이고, 원인만 특정하면 대부분 한 줄로 해결됩니다.

스택트레이스를 거꾸로 읽는 법 (ssh -vvv처럼)

스택트레이스는 위에서부터 읽으면 길을 잃습니다. ssh -vvv 로그 디버깅처럼 맨 아래부터 거꾸로 읽어야 진짜 원인이 보입니다. 실제 예시를 봅시다.

CODE
Error creating bean with name 'orderController':       ← ① 누가: orderController 생성 중
  Unsatisfied dependency expressed through constructor parameter 0;  ← ② 무엇을: 생성자 0번 파라미터 주입 실패
  nested exception is
  org.springframework.beans.factory.NoSuchBeanDefinitionException:
  No qualifying bean of type 'com.example.PaymentService' available:  ← ③ 왜: PaymentService 빈이 없음
  expected at least 1 bean which qualifies as autowire candidate

여기서 3요소만 뽑으면 끝납니다.

  1. 누가 (생성 실패한 빈): orderController
  2. 무엇을 (주입받으려던 대상): 생성자 파라미터 0번
  3. (근본 원인): NoSuchBeanDefinitionExceptionPaymentService 빈이 컨테이너에 없음

맨 아랫줄 예외 타입에 따라 원인 방향이 갈립니다.

맨 아래 예외 메시지의미의심 원인
NoSuchBeanDefinition: No qualifying bean ... expected at least 1빈이 0개컴포넌트 누락 / 스캔 범위 밖 / 조건부 빈 미생성
NoUniqueBeanDefinitionException: expected single matching bean but found 2빈이 2개 이상같은 타입 다중 등록, @Qualifier 필요
Requested bean is currently in creation / circular reference서로를 참조생성자 순환참조

원인 6가지 진단 표 + 복붙 해결 코드

먼저 한눈에 보는 매핑 표입니다.

#에러 단서원인해결책
1No qualifying bean ... expected at least 1@Component 누락 또는 스캔 범위 밖어노테이션 부착 / @ComponentScan(basePackages=...)
2expected single matching bean but found 2구현체 다중@Qualifier / @Primary
3currently in creation생성자 순환참조설계 분리 / @Lazy
4빈이 통째로 없음@ConditionalOnProperty·@Profile 미충족프로퍼티/프로파일 활성화
5NoUniqueBeanDefinitionException동일 타입 빈 2개@Primary 또는 명시 주입
6테스트에서만 실패슬라이스 컨텍스트에 빈 누락@MockBean / 슬라이스 범위 조정

원인 1. 컴포넌트 누락 또는 스캔 범위 밖

가장 흔합니다. @SpringBootApplication은 자신이 위치한 패키지와 그 하위만 스캔합니다. com.example.common 같은 별도 루트에 빈이 있으면 못 잡습니다.

JAVA
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.app", "com.example.common"})
public class Application { }

물론 클래스에 @Service/@Component 자체를 빠뜨린 경우도 많으니 먼저 확인하세요.

원인 2 & 5. 구현체 다중 → @Qualifier / @Primary

PaymentService 구현체가 KakaoPayService, NaverPayService 둘이면 스프링은 무엇을 주입할지 몰라 NoUniqueBeanDefinitionException을 던집니다.

JAVA
@Service @Qualifier("kakaoPay")
public class KakaoPayService implements PaymentService { }

@Service @Primary  // 기본 후보 지정
public class NaverPayService implements PaymentService { }

// 주입 시 명시 선택
public OrderController(@Qualifier("kakaoPay") PaymentService paymentService) { ... }

원인 3. 생성자 순환참조 → @Lazy

A가 B를, B가 A를 생성자로 주입하면 순환참조입니다. Spring Boot 2.6+ 부터 spring.main.allow-circular-references 기본값이 false라 기동이 곧바로 막힙니다(과거 필드 주입으로 숨어 있던 문제가 생성자 주입 권장으로 조기에 드러나는 셈입니다). 정석은 책임 분리지만, 급할 땐:

JAVA
public AService(@Lazy BService bService) {
    this.bService = bService;
}

원인 4. 조건부 빈 미생성

@ConditionalOnProperty 조건이 안 맞으면 빈 자체가 안 만들어집니다.

JAVA
@Bean
@ConditionalOnProperty(name = "feature.pay.enabled", havingValue = "true")
public PaymentService paymentService() { ... }

application.ymlfeature.pay.enabled: true를 넣어야 빈이 생깁니다. @Profile("prod")도 마찬가지입니다.

원인 6. 테스트에서만 실패

@WebMvcTest는 컨트롤러 슬라이스만 로딩하므로 서비스 빈이 없습니다. 의존 빈은 @MockBean으로 채워주세요.

JAVA
@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @MockBean PaymentService paymentService;
    @Autowired MockMvc mockMvc;
}

실무 한마디

저는 신규 프로젝트 셋업 직후 가장 먼저 패키지 구조를 com.example.app 루트 하나로 정렬합니다. 멀티 루트 패키지에서 basePackages를 빠뜨려 발생하는 원인 1번이 전체 빈 주입 이슈의 절반 이상을 차지하더군요. 그리고 자동설정 빈이 안 생길 땐 라이브러리 코드가 아니라 build.gradle 의존성 누락을 먼저 의심하는 게 빠릅니다.

흔한 함정 & 검증 루틴

  • 멀티모듈: core 모듈의 빈이 api 모듈에서 안 잡히면, 의존성과 함께 스캔 경로(@ComponentScan)에 그 패키지가 포함됐는지 확인하세요.
  • 의존성 누락으로 자동설정 빈 미생성: 라이브러리가 없으면 @ConditionalOnClass 자동설정이 통째로 비활성화됩니다.
GROOVY
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
  • @Autowired(required=false)·Optional 우회의 함정: 에러는 사라지지만 런타임에 NPE로 더 늦게 터집니다. 근본 원인을 가리는 임시방편일 뿐입니다.
  • Actuator로 실제 등록 빈 확인: 추측 대신 눈으로 봅시다.
PROPERTIES
management.endpoints.web.exposure.include=beans

/actuator/beans를 호출해 문제의 빈 이름이 목록에 있는지 확인하면 "스캔이 안 된 건지, 조건 때문에 안 만들어진 건지"가 즉시 갈립니다. 참고로 Spring Boot 3.x는 Jakarta 네임스페이스(jakarta.*) 전환 후라 javax.* 기반 라이브러리는 빈 스캔/자동설정에서 누락될 수 있고, GraalVM Native Image에서는 리플렉션 기반 빈 등록이 빌드타임에 빠질 수 있어 별도 힌트가 필요합니다.

결론: 진단 체크리스트 1장 요약

  1. 스택트레이스 맨 아래부터 읽어 예외 타입 확인
  2. No qualifying bean → 컴포넌트 누락/스캔 범위/조건부 빈
  3. expected single ... found 2@Qualifier/@Primary
  4. currently in creation → 순환참조, 설계 분리 또는 @Lazy
  5. 테스트만 실패 → 슬라이스 범위 + @MockBean
  6. 헷갈리면 /actuator/beans로 실제 등록 여부 확인

"빨간 줄 200개"는 사실 맨 아래 한 줄을 위한 호위무사일 뿐입니다. 거꾸로 읽기를 습관화하고, 평소 Actuator로 빈 목록을 사전 점검하는 루틴을 들이면 기동 실패는 더 이상 무섭지 않습니다.

자주 묻는 질문 (FAQ)

Q. @Component를 붙였는데도 No qualifying bean이 뜹니다. A. 거의 100% 스캔 범위 밖입니다. 해당 클래스 패키지가 @SpringBootApplication이 위치한 패키지의 하위가 아니라면 @ComponentScan(basePackages=...)에 명시하세요.

Q. @Repository는 인식되는데 제 클래스만 안 됩니다. A. 그 Repository는 자동설정/스캔 범위 안에 있고 여러분 클래스만 밖이라는 신호입니다. 패키지 위치와 어노테이션 부착 여부를 함께 확인하세요.

Q. 테스트에서만 빈 주입이 실패합니다. A. @WebMvcTest·@DataJpaTest 같은 슬라이스는 일부 빈만 로딩합니다. 필요한 의존성은 @MockBean으로 채우거나, 전체 컨텍스트가 필요하면 @SpringBootTest를 쓰세요.

Q. 순환참조인지 어떻게 알 수 있나요? A. 메시지에 currently in creation 또는 circular reference가 보이면 확정입니다. Spring Boot 2.6+는 기본적으로 막으므로 기동 즉시 드러납니다.

Q. 구현체가 2개일 때 무조건 @Primary를 써도 되나요? A. "기본 구현이 명확히 하나"일 때만 @Primary가 적절합니다. 상황별로 골라 써야 한다면 주입 지점마다 @Qualifier로 명시하는 편이 안전하고 의도가 분명합니다.

✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 ·

Comments

Be the first to comment.