Spring Data JPA - JPA 원리

Spring Data JPA

백기선님의 강의인 Spring Data JPA 강의를 듣고 공부한 내용을 정리한 글

JPA

드디어(?) 스프링 데이터 JPA에 대해서 학습해보자.

@Repository
class PostRepository {

    @PersistenceContext
    lateinit var entityManager: EntityManager

    fun add(post:Post): Post {
        entityManager.persist(post)
        return post
    }

    fun delete(post:Post) {
        entityManager.remove(post)
    }
    fun findAll(): MutableList<Any?>? {
        // JPQL 사용
        return entityManager.createQuery("SELECT p FROM Post As p")
                .resultList
    }

}

여기서 @Autowired가 아닌 @PersistenceContext를 사용한 이유는 최대한 스프링 코드를 감추기 위해서 이다.

스프링 코드를 감추는 이유는 스프링의 철학과도 연결되는 이유인데, 비침투성 - 스프링의 코드를 최대한 노출하지 않겠다는 철학을 따랐기 때문이다.

위의 JPA는 딱 보면 알겠지만 작성하기가 번거로웠다.

그래서 이러한 구현을 반복하고 싶지 않았던 개발자들은 GenericRepository라고 하는 별도의 프레임워크가 유행했던 시절이 있었다. (호랑이 담배피던 시절?)

그러나 그 이후 스프링 데이터 JPA는 아주 획기적인 변화가 생기는데 그것이 바로 가장 진보된 형태인 JpaRepository 인터페이스이다.

interface PostRepository: JpaRepository<Post,Long>{

}

끝이다! 이것이 스프링 데이터 JPA의 가장 현대적인 구현이다.

JpaRepository에서 제네릭 타입의 첫 번째 인자는 Entity의 타입이고 두 번째 인자는 Entity의 PK(id)이다.

스프링 부트를 사용했기 때문에 @EnableJpaRepositories를 굳이 명시하지않아도 된다.

원래라면 @Configuration이 붙은 클래스에 추가했었어야했지만, 스프링 부트에서 이를 자동으로 적용해주기 때문에 굳이 추가하지 않아도 된다.

그래서 Repository는 특별한 설정없이 빈으로 등록된다.

JpaRepository는 이미 JPA에서 충분한 테스트를 거쳐 제공되는 클래스이므로 굳이 테스트를 만들 필요는 없다. (학습용 테스트라면 OK)

그렇다면 어떻게 동작하는 것인지, 어떻게 빈으로 등록되었고 주입 받은 것인지 알아보자.

앞서 말했듯이 원래는 @EnableJpaRepositories가 있어야한다.

@EnableJpaRepositories의 내부를 살펴보면 아래와 같은 애노테이션들이 있다.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(JpaRepositoriesRegistrar.class)
public @interface EnableJpaRepositories {
  ...

여기서 Import에 JpaRepositoriesRegistrar가 있는데, 이 Import가 해당 클래스를 빈으로 등록해주는 애노테이션이다.

@EnableJpaRepositories@Import에서 JpaRepository를 빈으로 등록한다는 사실을 알아냈다.

JpaRepositoriesRegistrar를 조금 더 자세히 살펴보자면,

/**
 * {@link ImportBeanDefinitionRegistrar} to enable {@link EnableJpaRepositories} annotation.
 *
 * @author Oliver Gierke
 */
class JpaRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
...

주석 상단에 ImportBeanDefinitionRegistrar라고 적혀있는 것을 볼 수 있다.

ImportBeanDefinitionRegistrar은 빈을 정의할 수 있는 특수한 형태의 인터페이스이다.

이 인터페이스는 스프링 프레임워크이 제공해주는 인터페이스고 이 인터페이스를 구현하는 구현체가 많다.

이 인터페이스가 의미하는 바는 빈을 프로그래밍을 통해 등록할 수 있게 해주는 기능을 갖고 있다.

즉, 프로그래밍을 통해 JpaRepository 또는 JpaRepository를 상속받은 인터페이스를 찾아서 빈으로 등록할 수 있다는 말이다.

물론 ImportBeanDefinitionRegistrar로 JpaRepository를 등록하는 과정은 매우 복잡할 것이다.

모든 JpaRepository와 그 JpaRepository를 상속받는 인터페이스들을 다 찾아야 하니까.

Reference

인프런 백기선님의 스프링 Data JPA



© 2022. by minkuk

Powered by minkuk