안녕하세요. 아직도 취준중인 백수, 청주는사과아님 입니다.
이전 포스팅에서 Spring-data-jpa 의 Non-bean instance loaded to context 에러 를 발견해 기록 했었는데요.
이제 시간이 지나 어느정도 변경점이 완료된 것 같아 유지보수 포스팅(?) 을 작성해 보고자 합니다.
이전에 발견했던 에러를 간단히 다시 회고시키겠습니다.
에러는 아래와 같은 상황에서 일어났습니다.
interface SomeJpaInterface extends JpaRepository< ... > { /* ... */ }
// 그냥 이름이 (SomeJpaInterface) + (Impl) 일 뿐인
// Spring 과 아무런 관련이 없는 클래스
class SomeJpaInterfaceImpl {
// this is just a random instance
// so it should NOT be loaded to spring context
}
위처럼 JPA 인터페이스의 이름이 SomeJpaInterface 이고, Spring 과 관련 없는 SomeJpaInterfaceImpl 가 존재할 때, 이 클래스가 Spring Context 에 적재되는 에러였습니다.
저번 포스팅에서는 위 에러를 발견 후, 공식 github 에 물어 답변을 기다리던 상태였습니다.
Spring-data-jpa 형님들의 답변issue 를 올리고 다음날 Spring-data-jpa 형님의 댓글이 달렸습니다.
형님의 답변에 의하면 Custom Repository 자체는 1.x 버전대에 만들어져 (인터페이스 이름) + Impl 인 이름 만으로 Custom Repository 를 선언하였다고 합니다.
즉, 지금은 [1] 처럼 사용하라 문서에 나와있지만 옛날에는 [2] 방식 이었다는 것이지요.
// [1] : 지금은 spring-data-jpa 3.x 버전대
// CustomRepository 를 extends 해서 **CustomRepository 를 사용함을 명시**
interface MyJpa extends JpaRepository< ... >, CustomRepository {/* ... */}
interface CustomRepository {
/* ... Custom query methods ... */
}
class CustomRepositoryImpl implements CustomRepository {
/* ... Custom query method implements ... */
}
// [2] : 옛날 옛적 호랑이 담배피던 1.x 시절
// 우리 에러 났었던 예시랑 동일
interface MyJpa extends JpaRepository< ... > {/* ... */}
class MyJpaImpl {
// this were `Custom Repository` on Spring-data-jpa 1.x
}
그래서 형님은 1.x 버전대의 코드 때문에 위 에러가 발생한 것이라 의심하였고, 몇번의 추가적인 대화 끝에 이에 착수하겠다 하였습니다.
Spring-data-jpa 의 Custom Repository Implementations 문서그러부터 몇일이 지나 확인해보니 이전 올렸던 issue 가 spring-data-commons 로 옮겨졌고, 관련된 pull request 가 만들어졌습니다.
한번 pr 변경점을 확인해보니 Custom Repository Implementations 문서가 변경되고 있었습니다.
위 내용을 각각 정리하면 다음과 같습니다.
Note
Custom Repository를 만들 때Impl접미사를 붙이십시오.
이 때@Enable<StoreModule>Repositories(repositoryImplementationPostfix = ...)를 통해Impl대신 다른 접미사를 사용할 수 있습니다.
Warning
역사적(?) 으로
Custom Repository 구현체는 아래와 같은 특정 네이밍 패턴 에 기반해 탐색됩니다.interface UserRepositoryCustom { public void someCustomMethod(User user); } class UserRepositoryImpl implements UserRepositoryCustom { public void someCustomMethod(User user) { // Your custom implementation } }이는 한
Custom Repository마다 단 하나 의 구현체만 가능토록하기 위한 의도입니다.즉,
Custom Repository 인터페이스와 동일한 패키지에 존재 하고 (인터페이스 이름) + 접미사 인 구현체는Custom Repository 구현체로 간주 되며, 이는 의도치 않은 행동을 야기할 수 있습니다.때문에 우리는 "이름에 기반한 단일 Custom Repository 구현체 방식(?)"
(single-custom implementation naming)의 만료를 고려중이며, 이러한 사용 방식(pattern)을 권장하지 않습니다.
대신 "fragment 에 기반한 프로그래밍 모델(???)"(fragment-based programming model)로 이주하십시오.
single-custom implementation naming, fragment-based programming model 이 번역이 올바른지는 모르겠지만, 어찌되었든 이름에 기반한 Custom Repository 방식을 deprecated 하려는 것 처럼 보입니다.
현재 앞서 보여드린 문서 변경점 은 실제 공식 문서에도 적용되었습니다.
사실 포스팅으로 정리하기 전 까지만 해도 문서만 바꿔두고 안고친다 는 줄 알았는데, deprecated 시키려 하는 걸 보니 언젠가 라이브러리에 위 에러가 고쳐질 수도 있을 것 같다는 생각이 드네요.
이 에러를 물어보면서도 내가 그냥 멍청한게 아닐까, 진짜 물어보는게 맞나 등 참 많이 고민했었는데, 실제로 이렇게 답변 받고 확인을 받으니 시원하네요.
역시 모를땐 그냥 물어보는게 가장 빠르고 확실한 것 같습니다.