빈이 분명히 있는데 can't resolve dependencies가 난 이유 — 패키지 위치
문제 발생
서비스와 리포지토리를 분명히 만들었는데 앱이 뜨지 않았습니다.
Field service in com.example.api.PostController required a bean of type
'com.example.core.PostService' that could not be found.@Service도 붙어 있고 오타도 없었습니다. 패키지 구조는 이랬습니다.
com.example.api ← MyApplication.java (메인 클래스)
com.example.core ← PostService.java원인 분석
스캔 시작점이 메인 클래스의 패키지입니다. Spring Boot 문서가 설명합니다 — @SpringBootApplication 애노테이션은 보통 메인 클래스에 놓이며, 특정 항목들에 대한 기본 "검색 패키지"를 암묵적으로 정의합니다. 예로 JPA 애플리케이션이라면 @SpringBootApplication이 붙은 클래스의 패키지가 @Entity 검색의 기준이 됩니다.
우리 구조에서는 기준이 com.example.api이므로 형제 패키지인 com.example.core는 스캔 범위 밖입니다. 빈은 만들어진 적이 없고, 주입할 것을 찾지 못한 것입니다.
문서의 권고가 곧 해법입니다 — 메인 애플리케이션 클래스를 다른 클래스들보다 위의 루트 패키지에 두는 것을 일반적으로 권장하며, 루트 패키지를 쓰면 컴포넌트 스캔이 우리 프로젝트에만 적용됩니다.
기본 패키지에 대한 경고도 있습니다 — 패키지 선언이 없는 클래스는 "기본 패키지"에 속하는데, 이는 일반적으로 권장되지 않으며 피해야 합니다. @ComponentScan, @EntityScan, @SpringBootApplication을 쓰는 앱에서는 모든 jar의 모든 클래스를 읽게 되어 특히 문제가 됩니다.
해결 방안
- 메인 클래스를 루트 패키지로 올립니다. 문서가 제시하는 구조 그대로입니다.
com.example.myapplication
├─ MyApplication.java
├─ customer/ (Customer, CustomerController, CustomerService, CustomerRepository)
└─ order/ (Order, OrderController, OrderService, OrderRepository)-
기능별로 묶습니다. 계층별(
controllers,services)이 아니라 도메인별로 나누면 스캔 범위와 응집도가 함께 정리됩니다. -
@ComponentScan으로 억지로 넓히지 않습니다. 스캔 경로를 손으로 나열하기 시작하면 새 패키지를 추가할 때마다 같은 오류가 반복됩니다 — 구조를 고치는 편이 낫습니다. -
라이브러리 모듈의 빈은 명시적으로 가져옵니다. 다른 아티팩트의 빈이 필요하다면 자동 설정(
@AutoConfiguration)이나@Import처럼 의도가 드러나는 방법을 씁니다. -
기본 패키지를 쓰지 않습니다. 예제 코드를 옮겨오다
package선언이 빠지는 경우가 실제로 생깁니다. -
오류 메시지를 끝까지 읽습니다. Spring Boot의 실패 분석기는 "빈이 없다"와 함께 후보 클래스가 스캔되지 않았을 가능성까지 알려줍니다 — 그 문장이 패키지 구조를 보라는 신호입니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.