jpa

[jpa] Spring Data Jpa는 왜 interface만 생성해줘도 작동할까? + Spring Data Jpa 확장하기

우주유령 2023. 8. 8. 11:24
728x90
반응형

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 { … }

 

 

 

 

 

참고

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.customize-base-repository

 

Spring Data JPA - Reference Documentation

Example 121. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

 

728x90
반응형