Spring Data Jpa는 왜 interface만 생성해줘도 작동하는지에 대한 궁금증이 생겼다. 일단 먼저 spring data jpa의 기본적은 사용법부터 잠깐 보자.
Spring Data Jpa사용법
interface
JpaRepository를 extends받아서 새로운 interface를 만들어 사용한다.
public interface CrudRepository<T, ID> extends Repository<T, ID> { //Repository는 marker repository
//CrudRepository는 기본적인 CRUD내용을 담고있음
public interface PagingAndSortingRepository extends CrudRepository<T, ID> {...}
//PagingAndSortingRepository는 paging과 sorting관련 내용을 담고 있음
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {...}
//JpaRepository는 그 외의 추가적인 내용을 담고 있음
public interface MyRepository extends JpaRepository<T, ID> {...}
Implementation
configuration에 @EnableJpaRepositories를 달아주면 imple이 생성된다.
모든 마법은 @EnableJpaRepsitories에서 일어난다.
@Configuration
@EnableJpaRepositories("com.acme.repositories")
class ApplicationConfiguration {
@Bean
EntityManagerFactory entityManagerFactory() {
// …
}
}
@EnableJpaRepsitories
아래와 같은 속성들이 있다.
- basePackages : default는 @SpringBootApplication에서 설정한 bean scan범위
- repositoryBaseClass : baseRepository를 설정한다.
@EnableJpaRepositiries가 읽히면서 basePackages하위를 읽으며 repository를 bean으로 등록하고, 해당하는repository들이 instance화 될 때 Impl의 생성자가 실행된다.
그래서 interface만 생성해도 작동하는 것이다. 기본적으로 JpaRepository는 SimpleJpaRepository라는 Impl을 사용한다.
Spring Data Jpa 확장하기
이 과정을 알면 spring data jpa를 확장 할 수도 있을 것이다.
먼저 Repository interface를 만들자
interface
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }
interface UserRepository extends MyBaseRepository<User, Long> { … }
BaseRepository는 다른 repository에서 상속받아서 사용하는 repository를 말한다. spring data jpa에서 기본적으로 제공하는 CRUD repository등이 baseRepository와 같다고 생각하면 된다.
이렇게 BaseRepository를 만들어서 다른 repository에서 상속받아 사용할 수 있게 만들었다.
JpaRepsoitory를 확장한 BaseRepsoitory를 등록해서 JpaRepository대신 사용하여 Repository를 custom할 수 있다.
Implementation
Impl을 만들어보자
class MyRepositoryImpl<T, ID>
extends SimpleJpaRepository<T, ID> {
private final EntityManager entityManager;
MyRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
// Keep the EntityManager around to used from the newly introduced methods.
this.entityManager = entityManager;
}
@Transactional
public <S extends T> S save(S entity) {
// implementation goes here
}
}
baseRepository설정
이제 config에서 repositoryBaseClass라는 속성에 custom한 repository의 impl 클래스를 달아주면 MyRepositoryImpl을 baseRepository로 인식한다. 이제 모든 곳에서 MyRepositoryImpl을 baseRepository처럼 사용할 수 있다.
@Configuration
@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class)
class ApplicationConfiguration { … }
참고