하........
개빡친다...
ShortenUrl 엔티티를 저장하는 다음과 같은 JPA Repository를 정의했다.
@Repository
public interface UrlRepositoryJpa extends JpaRepository<ShortenUrl, String> {
Optional<ShortenUrl> findByShortenUrl(String shortenUrl);
}
뭐 별거 없지?
해당 인터페이스는 infrastructure 패키지에 있었고, 결과적으로는 domain 패키지의 UrlRepository를 구현해야했기 때문에 JPA Repository를 구성으로 사용하는 Impl 클래스를 만들었다.
@Repository
@RequiredArgsConstructor
public class UrlRepositoryJpaImpl implements UrlRepository {
private final JpaUrlRepository jpaUrlRepository;
// UrlRepository 구현 내용..
}
전~혀 문제될 것이 없어 보였다. 없어 보였다! 그러나..
.. 의존성 cycle이 생겼다고?
2시간동안 개난리난리쌩난리.. @Component 붙였다 뗐다.. @Repository 붙였다 뗐다.. @Profile 건드려보고.. @AutoWired 붙였다가 뗐다가, setter 사용했다가, @Configuration + @Bean 조합 사용하다가, @RequiredArgsConstructor 대신 생성자를 직접 만들기도 하다가 final로 하니 마니 진짜 별의 별 짓을 다 했다.
Bean들의 연관관계를 아무리 그려도 circular dependency는 보이지 않았기 때문에 멘붕이 왔다. JpaRepository는 어디에도 의존하지 않아서 독자적으로 존재할 수 있는걸? 그러다 아무런 생각 없이 JpaRepository<ShortenUrl,String>을 상속한 인터페이스 이름을 UrlRepositoryJpa -> UrlJpaRepository로 바꿔봤다. 진짜 뭘 얼마나 시도했으면 클래스 이름까지 바꿔보는 시도를 했겠나? ㅋㅋ
결과는 성공.
....................
Bean 이름에 컨벤션따윈 없는 줄 알았다.
그런데.. Repository에 대한 구현체는 해당 클래스 이름 뒤에 "Impl" 접미사를 붙여야 Spring Data JPA 측에서 구현된 빈으로 관리를 해준다고 한다.
docs에서 "most important part"라고 강조까지 했다.
처음에 보여줬던 나의 코드에서 나의 JpaRepository 빈 이름은 "UrlRepositoryJpa"였다. 만약 내가 이 객체를 Repository로 그냥 사용했다면, Spring Data JPA측에서 해당 인터페이스의 구현체로 만든 "UrlRepositoryJpaImpl"를 이용했을 것이다. 그.러.나. 내 쪽에서 UrlRepositoryJpaImpl 이름을 먼저 채가버렸으니 구현체로 "UrlRepositoryJpaImpl"가 생성이 안된다. JpaRepository가 구현되기 위해선 UrlRepositoryJpaImpl 클래스가 필요한데, 내가 만든 UrlRepositoryJpaImpl에서 JpaRepository를 쓰려고 하니 circular dependency가 발생한것..!
그림으로 더 자세히 표현해보겠다.
- UrlRepositoryJpa 인터페이스에 대해, Spring Data JPA가 내부적으로 UrlRepositoryJpaImpl 이라는 클래스 구현체를 만들려고 시도한다.
- 그러나 내가 UrlRepositoryJpaImpl을 이미 선점했기 때문에.. 내가 선점한 클래스가 UrlRepositoryJpa의 구현체로 작동한다.
- 그런데? 내 UrlRepositoryJpaImpl은 UrlRepositoryJpa를 구성으로 두면서 의존한다. 여기서 circular dependency problem이 일어난 것이다...
그림에서도 화살표가 원을 그리는 것을 확인할 수 있따 TT
그렇기 때문에 인터페이스의 이름을 UrlJpaRepository로 바꿔주면, Spring Data JPA가 만든 구현체와 충돌하지 않는다.
기존에 있던 Circular Dependency가 사라졌다!
와...... 이 사소한 것 때문에 몇 시간을 날린거냐 대체?