Spring Boot NoSuchBeanDefinitionException 해결 — Bean을 못 찾는 이유 5가지
NoSuchBeanDefinitionException은 Spring 컨테이너가 의존성 주입 시 해당 타입의 Bean이 찾지 못할 때 발생한다. 원인은 ① 컴포넌트 스캔 범위 밖, ② 어노테이션 누락, ③ 구현체 복수 등록, ④ @Bean 미등록, ⑤ 조건부 Bean 조건 불충족 — 이 5가지로 압축된다.Spring Boot 프로젝트를 시작하면 이런 에러가 뜬다.
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.example.service.UserService' available:
expected at least 1 bean which qualifies as autowire candidate.
또는
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'userController':
Unsatisfied dependency expressed through field 'userService'
NoSuchBeanDefinitionException의 의미는 단 하나다: Spring IoC 컨테이너에 해당 타입의 Bean이 등록되어 있지 않다. 코드가 막아 보여도 등록이 안 되어 있으면 반드시 이 에러가 난다.
원인 1: 컴포넌트 스캔 범위 밖
@SpringBootApplication은 해당 클래스가 위치한 패키지와 그 하위 패키지만 스캔한다. 이 범위 밖의 클래스는 @Service를 붙여도 Bean으로 등록되지 않는다.
문제 구조:
com.example.app
└── Application.java ← @SpringBootApplication
com.example.service
└── UserService.java ← @Service 붙여도 스캔 안 됨
해결:
// 방법 1: Application을 최상위 패키지로 이동
// com.example → Application.java
// 방법 2: 스캔 범위 명시
@SpringBootApplication(scanBasePackages = {"com.example.app", "com.example.service"})
public class Application {}
// 방법 3: @ComponentScan 추가
@ComponentScan(basePackages = "com.example")
원인 2: @Component / @Service / @Repository 누락
어노테이션이 없으면 Spring은 그 클래스를 Bean으로 인식하지 않는다.
// ❌ 잘못된 예
public class UserService { // @Service 없음
public User findById(Long id) { ... }
}
// ✅ 올바른 예
@Service
public class UserService {
public User findById(Long id) { ... }
}
Lombok @RequiredArgsConstructor를 써도 마찬가지다. 어노테이션 없으면 Bean이 아니다.
원인 3: 인터페이스 구현체가 여러 개
PaymentService 인터페이스의 구현체가 KakaoPayService, NaverPayService 두 개라면 Spring은 어느 것을 주입할지 결정하지 못한다.
NoUniqueBeanDefinitionException:
expected single matching bean but found 2: kakaoPayService, naverPayService
해결:
// @Primary — 기본 구현체 지정
@Service
@Primary
public class KakaoPayService implements PaymentService {}
// @Qualifier — 주입 시 명시
@Autowired
@Qualifier("naverPayService")
private PaymentService paymentService;
// 변수명으로 지정 (변수명 = Bean 이름)
@Autowired
private PaymentService kakaoPayService;
원인 4: @Configuration에서 @Bean 등록 누락
외부 라이브러리 클래스는 @Configuration에 @Bean을 명시해야 한다. 이 과정 없이 @Autowired하면 에러가 난다.
// ❌ @Bean 미등록
@Configuration
public class AppConfig {
// RestTemplate 등록 없음
}
@Service
public class ApiService {
@Autowired
private RestTemplate restTemplate; // NoSuchBeanDefinitionException!
}
// ✅ @Bean 명시
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
원인 5: 조건부 Bean 조건 불충족
@ConditionalOnProperty 등이 붙은 Bean은 조건이 맞지 않으면 컨테이너에 등록 자체가 되지 않는다.
@Bean
@ConditionalOnProperty(name = "feature.payment.enabled", havingValue = "true")
public PaymentService paymentService() {
return new PaymentService();
}
# application.yml — 이 설정이 없으면 Bean 등록 안 됨
feature:
payment:
enabled: true
빠른 디버깅: 등록된 Bean 목록 확인
management:
endpoints:
web:
exposure:
include: beans
/actuator/beans에서 현재 등록된 모든 Bean을 확인할 수 있다. 문제의 Bean 이름이 목록에 없으면 등록이 안 된 것이다.
체크리스트
| 증상 | 원인 | 해결 |
|---|---|---|
| 어노테이션 있는데 에러 | 패키지 스캔 범위 밖 | scanBasePackages 추가 |
| 인터페이스 주입 에러 | 구현체 복수 등록 | @Primary 또는 @Qualifier |
| 외부 라이브러리 주입 에러 | @Bean 미등록 | @Configuration에 @Bean 추가 |
| 환경별로 다르게 동작 | 조건부 Bean 조건 불충족 | 프로퍼티 값 확인 |
자주 묻는 질문 (FAQ)
Q. @Autowired 없이 생성자 주입해도 같은 에러가 나나요?A. 네. 에러 원인은 Bean 등록 여부이지 주입 방식이 아니다. @RequiredArgsConstructor, 생성자 직접 선언, @Autowired 모두 동일하게 발생한다.
A. @ConditionalOnProperty나 @Profile로 환경별 Bean 등록을 제어하는 코드가 있을 가능성이 높다. application-prod.yml에 해당 프로퍼티가 누락됐는지 확인한다.
BeanCreationException과 NoSuchBeanDefinitionException은 다른 에러인가요?
A. BeanCreationException은 Bean 생성 도중 발생하는 상위 예외다. caused by 라인을 찾으면 내부 원인으로 NoSuchBeanDefinitionException이 포함된 경우가 많다.
정리
NoSuchBeanDefinitionException 진단 순서:
1. 클래스에 @Service / @Component / @Repository가 있는가?
2. 컴포넌트 스캔 패키지 범위 안에 있는가?
3. 구현체가 여러 개라면 @Primary 또는 @Qualifier로 지정했는가?
4. 외부 클래스라면 @Configuration에 @Bean으로 등록했는가?
5. 조건부 Bean이라면 조건이 충족되는가?
이 5단계를 순서대로 확인하면 원인이 반드시 나온다.
댓글 없음:
댓글 쓰기