작성
·
248
·
수정됨
0
안녕하세요. 최근 spring-data-jpa
를 공부하다 이상한 순환 참조 오류를 발견했습니다.
그런데 도통 납득이 되지 않아 여쭤보고자 질문 드립니다.
spring-data-jpa
를 사용하기 전, 저는 주로 MyBatis
를 아래처럼 주로 사용했습니다.
// 주로 mybatis interface 인 mapper 를 먼저 선언하고
@Mapper
public interface MyBatisMapper {/* ... */}
/* ------------ */
// DAO 객체에 주입해 사용하는 형태로 사용했습니다.
@Repository
public class MyBatisRepo {
private final MyBatisMapper mapper;
public MyBatisRepo(MyBatisMapper mapper) {
this.mapper = mapper;
}
/* 생략 */
}
그래서 JPA
에서도 이처럼 사용해 볼까 하는 마음에 연습하던 중, 순환참조 오류가 발생하였습니다.
아래는 spring-data-jpa
에서 오류가 발생한 코드입니다.
TestEntity
: 연습용 엔티티
@Entity
public class TestEntity {
@Id
private Long id;
}
DAO
인터페이스 : repository 규약
public interface TestRepo {
// 연습용이라 텅 비어있습니다.
}
JPA
인터페이스
public interface JPATestRepo extends JpaRepository<TestEntity, Long> {
// 연습용이라 텅 비어있습니다.
}
Repository
구현체
@Repository
public class JPATestRepoImpl implements TestRepo {
private final JPATestRepo jpaRepo;
public JPATestRepoImpl(JPATestRepo jpaRepo) {
this.jpaRepo = jpaRepo;
}
// 연습용이라 이후 아무 내용도 없습니다.
}
실행시 발생하는 에러
2024-10-19T19:46:00.760+09:00 WARN 66384 --- [testing] [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'JPATestRepoImpl' defined in file [/~~~/Desktop/Coding/testing/build/classes/java/main/core/testing/JPATestRepoImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: Error creating bean with name 'JPATestRepoImpl': Requested bean is currently in creation: Is there an unresolvable circular reference?
2024-10-19T19:46:00.761+09:00 INFO 66384 --- [testing] [ main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2024-10-19T19:46:00.762+09:00 INFO 66384 --- [testing] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2024-10-19T19:46:00.807+09:00 INFO 66384 --- [testing] [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2024-10-19T19:46:00.811+09:00 INFO 66384 --- [testing] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-10-19T19:46:00.825+09:00 ERROR 66384 --- [testing] [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌──->──┐
| JPATestRepoImpl defined in file [/~~~/Desktop/Coding/testing/build/classes/java/main/core/testing/JPATestRepoImpl.class]
└──<-──┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Process finished with exit code 1
콘솔 에러에 따르면 JPATestRepoImpl
가 자기 자신을 의존해 순환참조가 발생한다고 합니다.
하지만 JPATestRepoImpl
는 (코드에서 볼 수 있듯이) JPATestRepo
를 주입받을 뿐, 자기자신을 의존하고 있지 않습니다.
게다가 더 혼란스러운 점은 만약 JPATestRepoImpl
의 이름을 다른 것으로 바꾸면 (예를 들어 TestRepoJPAImpl)
거짓말처럼 순환 참조 오류가 없어집니다.
제가 추측하기로는 스프링이나 JPA
가 bean
이름을 헷갈려 발생하는 오류 같은데, 이를 헷갈려 하는 이유를 도통 모르겠습니다.
당연히 컴퓨터 재시작, 프로젝트 clean, rebuild, 프로젝트 재생성해 시도해봤지만 모두 같은 현상이 나타납니다.
도대체 어떤 이유 때문에 이런 현상이 일어나는 걸까요...?
Github repo : https://github.com/jbw9964/testing
답변 2
0
jpa에서 지원하는 네이밍 컨벤션 기능 때문에 그런 거 같습니다. XXXJpaRespository 인터페이스를 만들고 JpaRespository<E,T>, XXXJpaCustomRespository 인터페이스를 상속하면 XXXJpaCustomRespositoryImpl 에서 구현한 로직을 XXXJpaRespository만으로도 기본 jpa, 사용자 구현 기능을 둘 다 사용할 수 있습니다. 그래서 지금 사용하려는 JPATestRepo 구현체가 JPATestRepoImpl을 참조하기 때문에 생긴 에러 같습니다.
0
안녕하세요, 인프런 AI 인턴입니다.
정준상님께서 겪고 계신 문제는 Spring Data JPA의 기본적인 동작 방식에 의해 발생하는 것 같습니다. JPATestRepoImpl
라는 클래스명을 사용하고 계시기 때문에, Spring Data JPA는 이를 QueryDSL이나 JPA 사용자 정의 리포지토리 구현체로 인식할 가능성이 있습니다. 이러한 상황에서는 JPA 프레임워크가 해당 인터페이스의 구현체로 스스로를 참조하는 동시에 자동 생성된 클래스를 참조하려고 하여 순환 참조 오류가 발생할 수 있습니다.
이 문제를 해결하기 위해 다음과 같은 몇 가지 방법을 고려할 수 있습니다:
클래스명 변경: 이미 시도하셨던 것처럼, JPATestRepoImpl
대신 다른 클래스명(예: TestRepoJPAImpl
)을 사용하여 문제를 피할 수 있습니다.
사용자 정의 리포지토리와 일반적인 JPA 리포지토리의 분리: JPA 리포지토리를 사용하는 경우, Spring Data JPA가 제공하는 메서드를 직접 사용하여 구현체를 작성할 필요가 없으므로, 사용자 정의 리포지토리를 사용하는 부분은 별도의 구현체로 분리해야 합니다. 예를 들어, 사용자 정의 리포지토리는 TestRepoCustom
이라는 인터페이스로 나누고, 이를 구현한 TestRepoCustomImpl
을 생성하여 JPATestRepo
와 연결하지 않도록 하면 됩니다.
이 문제에 대한 더 자세한 내용은 Spring Data JPA Reference Documentation에서 찾을 수 있습니다.
문제가 잘 해결되길 바랍니다! 추가 질문이 있으시면 언제든지 말씀해 주세요.