CrudRepository, JpaRepository, Repository

박영준·2023년 3월 11일
1

Spring

목록 보기
14/58

Spring Data JPA 를 사용하면, 일반적으로 Repository 에서 다음의 인터페이스 中 하나를 상속하여 사용하게 된다.

  • CrudRepository
  • JpaRepository
  • Repository

(Spring Data Jpa에서 제공하는 인터페이스 사이의 상속관계)

아래로 갈 수록 저수준 모듈이며 기능 구현이 많음

1. CrudRepository

1) 정의

public interface AccountRepository extends CrudRepository<Account, Long> {

}

// 인터페이스가 비어 있어도, 아래의 메서드들은 호출이 가능
<S extends T> S save(S entity);

Optional<T> findById(ID id);

Iterable<T> findAll();

long count();

void deleteById(ID id);
...
  • CrudRepository의 경우, 메서드를 정의하지 않아도 간단한 CRUD 사용이 가능

2) 문제점

우리가 정의하지 않은 기능을 인터페이스로 제공하면, 문제가 발생할 수 있다.

예를 들어,
우리는 삭제 메서드는 제공하지 않기를 바라지만,
JpaRepository 는 삭제 메서드 & 필요 없는 다른 메서드들에 대한 인터페이스도 제공한다.

3) 해결법

우리가 필요한 메서드만 정의한다면,
시스템은 훨씬 간단명료해지고, 인터페이스로 제공하는 메서드 수는 훨씬 적어진다.
필요한 메서드가 있다면, 만들면 된다.

정말 필요한 메서드만 선언해서 사용함에 따라,
메서드의 재사용성이 높아진다.
→ 이는 쿼리 캐싱에 성공할 확률이 높아지는 효과

2. JpaRepository

1) JpaRepository 를 상속할 경우

(1) 메시지

public interface MemverRepository extends JpaRepository<Member, Long> {

}

이미 구현되어 있는 많은 메시지가 외부에 개방된다.
→ 해당 repository에 개방된 메시지 자동완성 도움을 받았을 때, 이 repository의 책임들이 무엇이고 역할이 무엇인지 정확히 파악할 수 없게 된다.

(2) 명세 역할의 인터페이스

(명세 역할 : OO조건을 충족한다면 이 타입으로 인정 가능하다. 내부 구현은 자유롭게 하되, OO조건에 대해서는 필수적으로 구현해야 한다... 등의 규약)

JpaRepository를 상속할 경우
총 4개의 인터페이스를 상속하는 결과가 만들어지고, 이로 인해 수많은 명세들이 함께 포함된다.
→ 그러나, 이들은 모두 MemberRepository 에 명시되지는 X

만약, MemberRepository 에 직접 필요한 메서드만 작성할 경우, 이런 문제들이 발생

  • 명시되지 않은 메서드들도 외부에 노출된다는 점
  • 구현체를 만들 때 명시되지 않았던 모든 메서드를 구현해야 한다는 점

(3) 테스트 더블

JpaRepository를 상속할 경우, 구현해야 할 메서드가 많아진다

내부를 다 구현하지 않아도 되긴하나,
그럼에도 불필요한 코드 라인이 발생하게 되고,
테스트 시점에서도 사용하지 않는 메서드들, 구현되지 않은 메서드들이 외부에 노출된다.

2) JpaRepository 상속 계층도

JpaRepository
CrudRepository, PagingAndSortingRepository 등...을 상속한다.
추가적인 편의 메서드들이 많이 선언되어 있다.

CrudRepository
CRUD 관련 메서드들이 선언되어 있다.

PagingAndSortingRepository
Sort 객체를 매개변수로 받는 페이징 처리 메서드가 선언되어 있다.

3. Repository

1) Repository 를 상속할 경우

(1) 메시지

public interface MemberRepository extends Repository<Member, Long> {

	List<Member> findAll();
}

기본으로 구현되는 메서드가 전혀 없다.
사용할 메서드들을 인터페이스 내부에 선언해두고, 선언된 메서드에 대해서만 외부에 개방된다.
→ 서비스 레이어에서 사용 시, 어떤 메시지를 보낼 수 있는지 한눈에 파악 & 비즈니스 로직에서 유의미한 책임들이 무엇이 있는지 파악 가능
→ 더 깔끔한 시스템 설계를 만들 수 있다.

(2) 명세 역할의 인터페이스

Repository를 상속할 경우

  • MemberRepository 인터페이스에 선언되어 있는 메서드들만이 명세의 전부이므로,
    완전히 독립적인 명세로서 역할을 할 수 있게 된다.
    → 이 구현체의 메서드들은 모두 MemberRepository 의 책임

  • 개방해야 할 메시지들임을 알 수 있다.

  • 구현체들이 어떤 것을 구현해야 하는지 명세로서 온전한 역할을 할 수 있게 된다.

(3) 테스트 더블

Repository를 상속할 경우, 꼭 필요한 메서드만 구현하면 된다.

이를 통해,
외부에 개방된 모든 메서드들은 비즈니스 로직에서 유의미한 책임들임을 유추 가능.
테스트 시점에서도 어떤 메서드를 사용해야 할지 선택이 수월함.


참고: Spring - JpaRepository가 아닌 Repository를 사용해야 하는 이유!
참고: JpaRepository vs Repository

profile
개발자로 거듭나기!

0개의 댓글