[Spring/스프링] Not a managed type 에러

sbj·2024년 2월 2일
0

ERROR.zip

목록 보기
19/19
post-thumbnail

2월 2일 오늘 정확히 7시간 6분 동안 이 에러때문에 코딩을 못 해서 억울해서라도 처음부터 끝까지 정리하는 에러


결론: 스프링 부트 3.x.x 이상은 Entity 임포트 시 Javax 사용

상황 정리

  1. 처음에 Repository, Service, Controller 전체 다 Not a managedtype 에러가 콘솔에 출력
  2. 열심히 구글링 후 Repository에 @NoRepositoryBean을 선언하라. > 실패
  3. 메인 Application에 @Componentscan, @EntityScan 등의 어노테이션에 각 패키지 명을 명시함

☺︎ @EntityScan vs @ComponentScan

결론적으로, 이 두 어노테이션은 완전히 다른 목적을 위해 존재한다. Spring 애플리케이션을 구성하는 데 있어서는 동일한 역할을 한다. @EntityScan은 Entity로 인식되길 원하는 패키지를 지정한다. 반면, @ComponentScan은 Spring 빈을 스캔해야 하는 패키지를 지정할 때 사용된다.

사용가능한 컴포넌트

@EntityScan@ComponentScan
Entity (JPA 사용 시)@Controller
@Service
@Repository
@Component

☺︎ @ComponentScan:

@Retention(value=RUNTIME)@Target(value=TYPE)@Documented@Repeatable(value=ComponentScans.class)public @interface ComponentScan은 @Configuration 클래스와 함께 사용하도록 컴포넌트 스캔 지시문을 설정하는 것이다.

이는 Spring XML의 <context:component-scan> 요소를 작성하는 것과 같은데, value() 속성을 특정 패키지를 스캔하도록 정의하는데 사용할 수 있다. 만약 특정 패키지가 정의되지 않으면, 이 어노테이션이 선언된 클래스의 패키지에서 스캔이 발생하는 것이다.

XML의 <context:component-scan>을 사용할 때, annotation-config이라는 속성이 있다. 이는 불리언 플래그로 "암시적 어노테이션 후처리기가 활성화되어야 하는지를 나타낸다. 기본값은 'true'이다." 간단히 말해서, true일 경우 @Controller, @Service, @Repository 등으로 주석 처리된 클래스의 객체를 만들고 의존성을 해결할 수 있다. false로 설정하면 모든 Spring Beans를 XML에 선언해야 하는 것이다.

그러나, @ComponentScan을 사용할 때는 거의 모든 경우에서 기본 어노테이션 구성 처리 (예: @Autowired 처리 등)가 가정된다.


► 예를 들어보자

쇼핑몰 앱을 만들고 있다고 가정해보자. 사용자는 제품을 검색하고, 제품을 장바구니에 추가하고, 결제를 할 수 있어야 한다. 이런 각각의 기능을 구현하는 코드들은 각각 다른 패키지에 있을 수 있다.

여기서 @ComponentScan 어노테이션은 스프링이 어떤 패키지를 찾아가면서 해당 패키지에 있는 컴포넌트(@Controller, @Service 등등)를 스프링 빈으로 등록할지 지정해주는 역할을 한다. 즉, @ComponentScan이 'com.example.shopping'을 스캔하도록 설정되어 있다면, 스프링은 'com.example.shopping' 패키지와 그 하위 패키지를 찾아다니면서 @Controller, @Service 등 표시된 클래스를 찾아서 스프링 빈으로 등록하게 된다.

다음으로 @EntityScan 어노테이션은 JPA가 데이터베이스와 상호작용하기 위해 사용하는 엔티티 클래스를 어디에서 찾을지 지정해준다. 예를 들어, 'com.example.shopping' 패키지에 있는 모든 JPA 엔티티 클래스를 데이터베이스 작업에 사용하려면, @EntityScan 어노테이션에 'com.example.shopping'을 지정하면 된다.


☺︎ @EntityScan

@EntityScan은 엔티티 클래스를 스캔하기 위한 자동-구성 시 사용되는 기본 패키지를 설정하는 것이다.

@EntityScan을 사용하면, 자동구성이 다음을 수행하게 된다:

  • JPA 엔티티를 위한 "스캔된 패키지"를 설정한다.
  • SessionFactory에서 사용되는 패키지를 설정한다.
  • Spring Data MongoDB, Cassandra 그리고 Couchbase 매핑 컨텍스트에 사용되는 '초기 엔티티 세트'를 설정한다.

그리고 이렇게 설정을 해주었다.

Service가 Repository Bean을 찾지 못 함

Description:

Parameter 0 of constructor in com.sb.musicapi.service.MusicService required a bean of type 'com.sb.musicapi.repository.MusicRepository' that could not be found.

Action:

Consider defining a bean of type 'com.sb.musicapi.repository.MusicRepository' in your configuration.

에러 풀어보면서 선언해둔 @NoBeanRepository 어노테이션 바로 삭제해주고 다시 구동했다.

그리고


시도한 것

  • @Configuration → 실패
  • @SpringBootApplication(패키지명지정) → 실패
  • 하위패키지 하나 더 생성해서 Main 어플리케이션이 최상위에 오도록 → 실패
|-->package1
|-->package2
|Main.java
  • Dependency : spring-boot-starter-data-jpa임(이게 맞는 Dependency) 을 확인하였음.

해결

Jakarta Persistence API (JPA)

스프링부트 3.2.2를 사용하고 있었다.

Spring Boot3 릴리즈 일부인 JPA 모듈이javax.persistence.api 대신 Jakarta Persistence API를 적용하도록 바뀌었다.

implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'

따라서, @EntityScan과 같은 JPA 어노테이션을 설정하더라도 엔티티를 찾지 못 한다. Spring Boot 버전 3을 사용하려면, Persistence API도 함께 마이그레이션 해줘야한다.

즉, 스프링 부트 3.x.x 이상에선 Jakarta API를 Import 해야한다.

javax.persistence.api 대신 Jakarta Persistence API를 적용하도록 변경되었다. 이때까지 javax를 import 해서 Entity 어노테이션을 사용했던 것이 문제였다. 내 Entity는 Entity가 아니었던 것이다. 해결해서 기쁘다. 그러니까 이런 문제를 겪고 있다면 @Entity 지정 시 Jakarta를 Import 해야한다..

profile
Strong men believe in cause and effect.

1개의 댓글

comment-user-thumbnail
2024년 7월 20일

와.... 감사합니다

답글 달기