[JPA] 엔티티(Entity)가 기본생성자를 가져야 하는 이유 ( Reflection )
조회시 사용되는 엔티티(Entity)는 기본생성자를 가지고 있어야 한다.
@Entity
@Data
public class Member {
@Id
public String name;
public int age;
public Member() {} //반드시 필요!
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
이유가 무엇일까?
◎ Reflection
EntityManger가 조회(find)를 요청하면 1차캐시에 원하는 엔티티가 없는 경우 DB에 SELECT문을 실행하여 조회한다. 그리고 결과를 1차캐시에 저장하고 엔티티 객체를 생성하여 반환(return)한다. 즉, 프로그램 실행 중에 동적으로 엔티티 객체를 생성해야 한다.
동적으로 객체를 생성하는 방법에는 두 가지가 있다.
① new 연산자
② Reflection
JPA는 new 연산자가 아닌 Reflection을 사용한다. Reflection을 사용하는 이유는 '문자열'로 클래스를 탐색하여 객체를 생성하기에 컴파일 단계에서 에러를 뱉지 않는다. new 연산자는 원하는 클래스를 import하지 않으면 컴파일과정에서 에러가 발생한다.
TestMain 클래스
public class TestMain {
public static void main(String[] args) {
Test test = new Test(); // new 연산자
}
}
Test 객체를 new 연산자로 만들고 컴파일을 시도해보았다.
can not find symbol이 발생한다. 그럼 Reflection을 보자.
import java.lang.reflect.Constructor;
public class ReflectionMain {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("org.example.reflection.Test"); // 문자열로 클래스 탐색
Constructor<?> constructor = clazz.getConstructor(); // 탐색된 클래스의 생성자 호출
Object object = constructor.newInstance(); // 호출된 생성자로 동적으로 객체생성
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
원하는 클래스를 '문자열'로 탐색하기에 원하는 클래스파일을 import하지 않아도 컴파일 과정에서 에러가 발생하지 않는다.
컴파일 단계에서 발생가능한 에러를 런타임 단계로 미루는 것이다. 이는 엄청난 유연성을 제공한다.
JPA는 엔티티를 자동으로 생성하여 클라이언트에 넘겨주어야 한다. 그런데 엔티티는 계속 새로 추가되고 컴파일 단계마다 엔티티를 관리해주어야 한다면 비효율일 수밖에 없다. Reflection은 엔티티가 계속 추가되어도 코드 수정없이 엔티티를 동적으로 생성할 수 있다. 클라이언트가 원하는 엔티티 클래스타입을 넘겨주면 JPA가 엔티티를 탐색한다.
entityManager.find(Member.class,"member2")
클라이언트는 Reflection이 엔티티 클래스를 탐색할 수 있도록 find 메소드에 파라미터로 클래스타입을 넣어주어야 한다.
◎ 엔티티(Entity)가 기본생성자를 가지고 있어야 하는 이유
JPA를 구현하는 Hibernate는 Reflection을 이용하여 객체를 동적으로 생성하는데, constructor.newInstance()로 객체를 생성한다. 그러므로 엔티티는 아규먼트 없는 기본생성자를 무조건 가지고 있어야 한다. 대신 Reflection은 클래스의 메타데이터에 접근하여 필드에 직접 데이터를 주입한다.
Reflection은 기본생성자로 객체를 생성하고 필드에는 메타데이터와 어노테이션을 분석하여 테이블의 컬럼과 매핑되는 데이터를 저장한다. 그리고 클라이언트에게 엔티티를 반환한다.
이처럼 JPA는 Reflection을 사용하여 객체를 동적으로 생성한다. 어노테이션부터 동적쿼리생성까지 JPA에는 Reflection 개념이 사용되는 부분이 많아 상당히 중요한 개념이다.
참고자료