View
반응형
[Spring Boot] BeanCreationException 원인 및 해결 방법 정리
Spring Boot 에러 해결 트러블슈팅
에러 메시지
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myService':
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.example.MyRepository' available
발생 상황
Spring IoC 컨테이너가 빈(Bean) 생성에 실패할 때 발생하는 예외
- 새로운 Service / Repository 클래스 추가 후 실행 시
- 의존성 변경 또는 클래스 구조 수정 후
- Spring Boot 버전 업그레이드 후
- 테스트 실행 시 ApplicationContext 로딩 실패
원인
- 빈 등록 누락 —
@Service,@Component등 어노테이션 미부착 - 생성자 충돌 — 생성자가 여러 개일 때 Spring이 선택 불가
- 순환 참조 — A → B → A 순환 의존 구조
- 프로퍼티 누락 —
@Value에 해당하는 값이 application.yml에 없음 - 구현체 미지정 — 인터페이스 구현체가 없거나 여러 개인데 지정 안 함
- 컴포넌트 스캔 범위 밖 — 빈 클래스가 메인 패키지 외부에 위치
해결 방법
1. 빈 등록 어노테이션 확인
가장 흔한 원인 클래스에 @Repository, @Service, @Component 어노테이션이 빠져있는 경우
// AS-IS: 어노테이션 누락
public class MyRepository {
...
}
// TO-BE: @Repository 추가
@Repository
public class MyRepository {
...
}
외부 라이브러리 클래스처럼 직접 수정이 불가한 경우, @Configuration + @Bean으로 수동 등록
@Configuration
public class AppConfig {
@Bean
public ExternalClient externalClient() {
return new ExternalClient("https://api.example.com");
}
}
2. 생성자 주입 문제
생성자가 여러 개면 Spring이 어느 것을 사용할지 판단 불가. Lombok @RequiredArgsConstructor 사용 시 해결
// AS-IS: 생성자 복수 → Spring 선택 불가
@Service
public class MyService {
private final MyRepository repository;
private final ExternalClient client;
public MyService(MyRepository repository) { ... }
public MyService(MyRepository repository, ExternalClient client) { ... }
}
// TO-BE: Lombok으로 단일 생성자 자동 생성
@Service
@RequiredArgsConstructor
public class MyService {
private final MyRepository repository;
private final ExternalClient client;
}
3. 순환 참조 해결
ServiceA → ServiceB → ServiceA 구조일 때 발생. Spring Boot 2.6+부터 기본 차단
방법 A: @Lazy로 지연 로딩
@Service
@RequiredArgsConstructor
public class ServiceA {
private final @Lazy ServiceB serviceB;
}
방법 B: Setter 주입으로 변경
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
방법 C: 공통 로직 분리 (권장) — 순환 구조 자체를 제거하는 방식
@Service
@RequiredArgsConstructor
public class CommonService {
private final SharedRepository sharedRepository;
}
4. 프로퍼티 누락
@Value로 주입하려는 키가 application.yml에 없을 때 발생. 기본값 설정으로 방지 가능
// AS-IS: 값 없으면 즉시 실패
@Value("${external.api.url}")
private String apiUrl;
// TO-BE: 콜론 뒤에 기본값 지정
@Value("${external.api.url:https://default-api.com}")
private String apiUrl;
5. 구현체 복수 시 지정
인터페이스에 구현체가 2개 이상일 때, @Primary 또는 @Qualifier로 대상 명시 필요
@Service
@Primary
public class MySqlUserRepository implements UserRepository { ... }
@Service
public class RedisUserRepository implements UserRepository { ... }
// 특정 구현체 지정
@Service
@RequiredArgsConstructor
public class UserService {
private final @Qualifier("redisUserRepository") UserRepository repository;
}
6. 컴포넌트 스캔 범위 확장
빈 클래스가 메인 Application 패키지 밖에 있으면 스캔 대상에서 제외됨. 멀티 모듈 프로젝트에서 자주 발생
@SpringBootApplication
@ComponentScan(basePackages = {
"com.example.myapp",
"com.example.external.library"
})
public class MyApplication { ... }
참고
- 에러 로그의
Caused by:체인을 따라가면 실제 원인은 가장 하단에 위치 logging.level.org.springframework.beans: DEBUG설정 시 빈 생성 과정 상세 확인 가능spring.main.allow-circular-references=true로 순환 참조 임시 허용 가능하나, 구조 리팩토링 권장- 테스트 환경에서는
@MockBean,@TestConfiguration으로 테스트 전용 빈 제공 - IntelliJ Spring 탭에서 등록된 빈 목록 확인 가능
728x90
반응형
reply
