1. Question

Spring에서 @Entity annotation을 사용하면 왜 빈 생성자가 필요할까?

2. Answer

@Entity annotation은 클래스가 JPA Entity임을 나타내며, 이 Entity는 데이터베이스 테이블에 매핑된다. 이 과정에서 JPA 구현체는 Entity 객체를 생성하고 관리하는 데 몇 가지 기준을 따른다.

  • 객체의 생성 및 재생성: JPA는 데이터베이스에서 엔티티(Entity)를 검색할 때 내부적으로 엔티티 인스턴스를 생성해야 한다. 이 과정에서 JPA는 리플랙션(Java Reflection)을 사용하여 엔티티 클래스의 객체를 직접 생성해야 한다. 리플랙션을 사용하여 객체를 생성하기 위해서는 클래스에 접근 가능한 빈 생성자가 필요하다. 만약 빈 생성자가 없다면, JPA 구현체는 인스턴스를 생성할 수 없어 오류가 발생한다.

  • 프록시 생성: JPA는 성능 최적화를 위해 지연 로딩(Lazy Loading)을 사용할 때 프록시를 생성한다. 프록시는 실제 객체의 대리 객체로 작동하며, 이 프록시 역시 빈 생성자를 사용하여 원본 Entity 클래스의 인스턴스를 생성한다.

이러한 이유로, JPA 스펙은 모든 엔티티에 기본 생성자를 요구한다. 기본 생성자는 public 또는 protected 접근 권한이 있어야 하며, 이는 JPA 구현체가 클래스 외부에서도 접근할 수 있도록 하기 위함이다. 개발자가 명시적으로 기본 생성자를 정의하지 않아도, 컴파일러는 자동으로 빈 생성자를 생성할 수 있지만, 다른 생성자가 명시적으로 정의되어 있는 경우에는 기본 생성자도 명시적으로 정의해야 할 수 있다.

3. Detail

A. Java Reflection

Java의 Reflection API는 런타임에 클래스, 인터페이스, 필드 및 메서드와 같은 프로그램의 메타데이터에 접근할 수 있게 해주는 기능이다. 이를 통해 개발자는 컴파일 시간에는 알 수 없는 클래스의 객체를 생성하거나, 메서드를 호출하고, 필드에 접근할 수 있다. 이러한 기능은 매우 유연하며 동적인 프로그래밍을 가능하게 한다.

B. 리플랙션에 빈 생성자가 필요한 이유

  • JPA를 사용하면, 자바 애플리케이션의 객체(엔티티)와 데이터베이스 간의 정보가 동기화된다. 즉, 데이터베이스의 최신 상태를 항상 객체에 반영하게 된다. 이 과정에서 객체를 처음 생성할 때는 ‘빈 생성자’를 통해 기본적인 형태만 만들어 놓고, 실제 데이터베이스의 내용은 나중에 객체에 채워 넣는다.

  • 필드 초기화 분리는 효율적인 데이터 관리를 가능하게 한다. 예를 들어, 데이터베이스에 저장된 정보를 기반으로 객체를 생성해야 할 때, JPA는 빈 객체를 먼저 만들고, 필요한 데이터만 선택적으로 그 객체에 채워 넣을 수 있다. 이는 메모리 사용을 최적화하고, 처리 속도를 높이는 데 도움을 줍니다.

C. 지연 로딩(Lazy Loading) VS 즉시 로딩(Eager Loading)

지연 로딩(Lazy Loading)

  • 정의: 엔티티를 로드할 때 연관된 객체들은 실제로 접근(사용)되는 순간에만 데이터베이스에서 로드된다.
  • 장점: 초기 로드 시간이 단축되고, 필요하지 않은 데이터는 로드되지 않아 메모리 사용량이 줄어든다. 이는 애플리케이션의 전체 성능을 향상시킬 수 있다.
  • 적절한 사용 시나리오: 연관된 데이터가 항상 필요하지 않은 경우나 연관된 데이터의 양이 많아서 로딩에 시간이 많이 걸리는 경우에 적합하다.

즉시 로딩(Eager Loading)

  • 정의: 엔티티를 로드할 때 연관된 객체들도 함께 즉시 로드된다. 즉, 처음 엔티티를 로드할 때 필요한 모든 데이터를 한 번에 가져온다.
  • 장점: 한 번의 데이터베이스 쿼리로 모든 필요 데이터를 로드하므로, 후속 작업에서 추가적인 데이터베이스 접근이 필요 없어 접근 속도가 빨라진다.
  • 적절한 사용 시나리오: 연관된 데이터를 거의 항상 함께 사용해야 하는 경우나 연관된 데이터의 양이 많지 않아 추가적인 성능 부담이 크지 않은 경우에 적합하다.

4. Reference

None

댓글남기기