[Spring Data JPA] @Repository를 생략해도 되는 이유

개요

 

 흔히 Spring Data JPA를 사용하기 위해서 JpaRepository 인터페이스를 사용할 때 아래와 같이 사용하고는 한다.

 

public interface MemberRepository extends JpaRepository<Member, Long> {
}

 

예전에 Spring Data JPA에 관해 공부할 떄 @Repository 어노테이션을 생략해도 된다는 말을 들었는데, 그 이유에 대해서 짧게 정리해보고자 한다.

 

@Repository

 

@Repository라는 어노테이션은 왜 사용하는 걸까? 

 

 

스프링부트 프로젝트에서 많이 사용되는 @Controller, @Service와 @Repository를 살펴보면, @Component 어노테이션이 있는 것을 확인할 수 있다. 스프링은 스프링 Main클래스에 등록되어 있는 @ComponentScan 어노테이션 안의 @ComponentScan 어노테이션을 통해서 @Component 어노테이션이 붙은 클래스들을 빈으로 등록해준다. 

 

이렇게 빈으로 등록된 Repository는 @Transactional 어노테이션을 통해서 스프링이 트랜잭션을 관리할 수 있게 되며, JPA 예외를 DataAccessException 하위 클래스로 변환하여 일괄처리 할 수 있게 돕는다.

 

 

여기까지는 다들 잘 아는 사실일테고, 나도 당연하다고 생각했는데 그렇다면 왜 Spring Data JPA를 사용할 떄 CRUD를 위한 JpaRepository를 구현하면 @Repository 어노테이션을 쓰지 않아도 되는걸까?

 

 

JpaRepository 인터페이스 분석해보기

 

 

 가장 먼저 Spring Data JPA의 핵심이 되는 JpaRepository가 어떤 인터페이스들을 상속받고 있는지 확인해보았다. 위의 클래스 다이어그램은 JpaRepository의 상위 인터페이스들을 나타내는 다이어그램이다. 상위 인터페이스들 중에 @Repository 어노테이션을 가지고 있는 인터페이스가 있을 것이라고 짐작했지만, @Repository 어노테이션은 존재하지 않았다.

 

 

 JpaRepository는 3개의 인터페이스를 상속받고 있다. ListCrudRepository, ListPagingAndSortingRepository, QueryByExampleExecutor라는 3개의 인터페이스가 그것인데, spring-data-jpa 모듈의 'org.springframework.data.jpa.repository'에 위치하는 JpaRepository와는 다르게 상위 인터페이스들은 모두 spring-data-commons 모듈의 'org.springframework.data.repository' 경로에 위치해 있었다.

 

 즉 JpaRepository가 상속받는 인터페이스들은 모두 Spring Data JPA가 아닌, JPA와 상관없이 Spring Data 모듈에서 제공하는 친구들이며, Spring Data 프로젝트에서 공통 모듈들에 대해서 기능(Spring Data JPA, Spring Data Redis, Spring Data JDBC 등)별로 구현체를 만들어 줌을 추측할 수 있었다.

 

왼쪽이 spring-data-jpa모듈 내의 JpaRepository, 오른쪽이 spring-data-common 모듈 내의 상위 인터페이스

 

 

 

 실제로 Spring Data JPA는 JpaRepository를 상속받은 커스텀 인터페이스에 있는 abstract method를 대상으로 하는 구현 클래스를 자동으로 생성해준다. (SimpleJpaRepository 클래스를 보면 제네릭 기반으로 구현되어 있는 것을 볼 수 있다) 따라서 마찬가지로 Spring Data 프로젝트에서 @Repository의 역할을 하는 기능도 제공해줄 것이라고 추측할 수 있었다.

 

 

해결

 

답은 Spring Data JPA 자체에 있었다.

 

 

 오른쪽 위를 보면 JpaRepository는 'org.springframework.data.repository' 패키지의 Repository 인터페이스를 상속받는 것을 확인할 수 있었는데, 해당 인터페이스를 구현한 클래스는 컴포넌트 스캔의 대상이 된다고 한다.