스프링 데이터 JPA 리포지토리는 인터페이스만 정의하고 구현체는 스프링이 자동으로 생성한다. 만약 인터페이스를 개발자가 직접 구현하려면 구현해야 하는 기능이 너무나도 많다. 특정 메서드만 따로 구현하여 사용하고 싶다면 사용자 정의 리포지토리를 구현하면 된다.
public interface MemberRepositoryCustom {
List<Member> findMemberCustom();
}
우리가 만든 커스텀 리포지토리의 구현 클래스를 생성한다. 이때 클래스의 이름은 반드시 (리포지토리 이름 + Impl)로 생성해야 한다. 그렇게 해야 스프링 데이터 JPA가 인식해서 스프링 빈으로 등록해준다.
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepositoryCustom {
private final EntityManager em;
@Override
public List<Member> findMemberCustom() {
return em.createQuery("select m from Member m")
.getResultList();
}
}
Jpa Repository에 우리가 만든 커스텀 리포지토리를 상속해준다. (인터페이스끼리 상속)
public interface MemberRepository extends JpaRepository<Member, Long>, MemberRepositoryCustom {
}
List<Member> result = memberRepository.findMemberCustom();
<repositories base-package="study.datajpa.repository" repository-impl-postfix="Impl" />
@EnableJpaRepositories(basePackages = "study.datajpa.repository", repositoryImplementationPostfix = "Impl")
참고: 실무에서는 주로 QueryDSL이나 SpringJdbcTemplate을 함께 사용할 때, 사용자 정의 리포지토리 기능을 자주 사용한다. 물론 항상 사용자 정의 리포지토리가 필요한 것은 아니다. 그냥 임의의 리포지토리를 만들어도 된다.
예를들어 MemberQueryRepository를 인터페이스가 아닌 클래스로 만들고 스프링 빈으로 등록해서 그냥 직접 사용해도 된다. 물론 이 경우 스프링 데이터 JPA와는 아무런 관계 없이 별도로 동작한다.
스프링 데이터 2.x 부터는 사용자 정의 구현 클래스에 (리포지토리 인터페이스 이름 + Impl) 을 적용하는 대신에 (사용자 정의 인터페이스 명 + Impl) 방식도 지원한다. 예를 들어 위 예제의 MemberRepositoryImpl 대신에 MemberRepositoryCustomImpl 같이 구현해도 된다
기존 방식보다 이 방식이 사용자 정의 인터페이스 이름과 구현 클래스 이름이 비슷하므로 더 직관적이다. 추가로 여러 인터페이스를 분리해서 구현하는 것도 가능하기 때문에 새롭게 변경된 이 방식을 사용하는 것을 더 권장한다.
@RequiredArgsConstructor
public class MemberRepositoryCustomImpl implements MemberRepositoryCustom {
private final EntityManager em;
@Override
public List<Member> findMemberCustom() {
return em.createQuery("select m from Member m")
.getResultList();
}
}