You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
결론부터 정리, 엔티티는 파라미터가 없는 기본 생성자가 필요하며 이는 public 또는 protected여야 한다.
JPA Reflection
EntityManger가 조회(find)를 요청하면 1차캐시에 원하는 엔티티가 없는 경우 DB에 SELECT문을 실행하여 조회한다. 그리고 결과를 1차캐시에 저장하고 엔티티 객체를 생성하여 반환(return)한다. 즉, 프로그램 실행 중에 동적으로 엔티티 객체를 생성해야 한다.
동적으로 객체를 생성하는 방법에는 두 가지가 있다.
① new 연산자
② Reflection
JPA는 new 연산자가 아닌 reflection을 사용한다.
new 연산자는 원하는 클래스를 import하지 않으면 컴파일과정에서 에러가 발생하지만, reflection은 '문자열'로 클래스를 탐색하여 객체를 생성하기에 컴파일 단계에서 에러를 뱉지 않기 때문이다.
🍀 Java Reflection API란?
구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 Java API -> 클래스 이름만으로 클래스 정보를 얻을 수 있다.
이러한 Java Reflection을 활용하면 컴파일 시점이 아닌 런타임 시점에 동적으로 클래스를 객체화 하여 분석 및 추출 해낼 수 있는 프로그래밍 기법이다.
👉 어떻게 이런일이 가능한걸까?
자바로 만든 프로그램을 실행시키면 JVM이 소스 코드를 .class 파일로 변환시킨 뒤 static 영역에 저장하는데 Reflection은 해당 static 영역에 접근이 가능하기 때문에, 이름만으로 클래스 대한 대부분의 정보에 접근이 가능한 것이다. 하지만 생성자의 매개변수에 대한 정보에는 접근이 불가능하여 기본생성자로 객체를 생성하는 것이다.
JPA는 데이터를 DB에서 조회해온 뒤 객체를 생성할 때 Refalection을 사용한다. 때문에 위의 예시처럼 기본 생성자로 객체를 생성해야한다.
결론적으로 기본 생성자가 존재하지 않는다면 DB에서 조회해 온 값을 엔티티로 만들 때 객체 생성 자체가 실패하게 되기 때문에 , JPA에서는 기본 스펙으로 기본 생성자를 반드시 생성해 줄 것을 정해놓는 것이다.
🤔 그러면 객체 생성은 그렇다 치고 기본 생성자이면 필드 주입은 어떻게 해?
Reflection은 기본생성자로 객체를 생성하고 필드에는 메타데이터와 어노테이션을 분석하여 테이블의 컬럼과 매핑되는 데이터를 저장한다. 그리고 클라이언트에게 엔티티를 반환한다.
👉 그렇다면 기본 생성자를 private로 하면 안되는 이유는 무엇일까?
프록시 객체 간단히 보고 넘어가기.
예를 들어, Member 엔티티에 Team 엔티티가 매핑되어 있다고 가정해보자.
이때, Member member = em.find(Member.class, 1L); 로 Member 객체를 불러온 상황이다.
즉시 로딩의 경우, 위에서 언급했듯이 연관된 Team 엔티티까지 한번에 가져온다.
반면, 지연 로딩의 경우에는 Member 객체를 얻기위한 쿼리만 DB로 날린다. 그리고 가짜 프록시 Team 객체를 생성해둔다.
이후, 실제로 Team 객체가 사용되는 시점에 DB에서 가져와, 이 프록시 객체를 초기화시킨다.
지연 로딩으로 인해 프록시 객체를 사용하게 되는 경우 원본 엔티티를 상속한 프록시 객체를 생성하게 된다. 그 이후 실제 필요한 타이밍에 엔티티를 조회해 온 뒤 프록시 엔티티가 원본 엔티티를 참조하도록해야한다. 엔티티의 생성자가 private로 되어있다면 해당 엔티티를 상속한 프록시 엔티티를 만들수가 없다. 상속한 객체의 생성자는 반드시 부모 객체의 생성자 super를 호출해야 하는데, private이면 상속받은 클래스에서 호출할 수 없기 때문이다.
어려운 내용이 있었다면 이를 어떻게 해결하였나요?
x
어떤 자료를 참고하였나요?
곧 첨부할 예정 ...
The text was updated successfully, but these errors were encountered:
무엇을 알게 되었나요?
JPA Reflection
EntityManger가 조회(find)를 요청하면 1차캐시에 원하는 엔티티가 없는 경우 DB에 SELECT문을 실행하여 조회한다. 그리고 결과를 1차캐시에 저장하고 엔티티 객체를 생성하여 반환(return)한다. 즉, 프로그램 실행 중에 동적으로 엔티티 객체를 생성해야 한다.
동적으로 객체를 생성하는 방법에는 두 가지가 있다.
JPA는 new 연산자가 아닌 reflection을 사용한다.
new 연산자는 원하는 클래스를 import하지 않으면 컴파일과정에서 에러가 발생하지만, reflection은 '문자열'로 클래스를 탐색하여 객체를 생성하기에 컴파일 단계에서 에러를 뱉지 않기 때문이다.
🍀 Java Reflection API란?
구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 Java API -> 클래스 이름만으로 클래스 정보를 얻을 수 있다.
이러한 Java Reflection을 활용하면 컴파일 시점이 아닌 런타임 시점에 동적으로 클래스를 객체화 하여 분석 및 추출 해낼 수 있는 프로그래밍 기법이다.
👉 어떻게 이런일이 가능한걸까?
자바로 만든 프로그램을 실행시키면 JVM이 소스 코드를 .class 파일로 변환시킨 뒤 static 영역에 저장하는데 Reflection은 해당 static 영역에 접근이 가능하기 때문에, 이름만으로 클래스 대한 대부분의 정보에 접근이 가능한 것이다. 하지만 생성자의 매개변수에 대한 정보에는 접근이 불가능하여 기본생성자로 객체를 생성하는 것이다.
👉 잠깐! 위의 예시에서 에러가 나는데, 이유가 무엇일까?
JPA는 데이터를 DB에서 조회해온 뒤 객체를 생성할 때 Refalection을 사용한다. 때문에 위의 예시처럼 기본 생성자로 객체를 생성해야한다.
결론적으로 기본 생성자가 존재하지 않는다면 DB에서 조회해 온 값을 엔티티로 만들 때 객체 생성 자체가 실패하게 되기 때문에 , JPA에서는 기본 스펙으로 기본 생성자를 반드시 생성해 줄 것을 정해놓는 것이다.
🤔 그러면 객체 생성은 그렇다 치고 기본 생성자이면 필드 주입은 어떻게 해?
Reflection은 기본생성자로 객체를 생성하고 필드에는 메타데이터와 어노테이션을 분석하여 테이블의 컬럼과 매핑되는 데이터를 저장한다. 그리고 클라이언트에게 엔티티를 반환한다.
👉 그렇다면 기본 생성자를 private로 하면 안되는 이유는 무엇일까?
지연 로딩으로 인해 프록시 객체를 사용하게 되는 경우 원본 엔티티를 상속한 프록시 객체를 생성하게 된다. 그 이후 실제 필요한 타이밍에 엔티티를 조회해 온 뒤 프록시 엔티티가 원본 엔티티를 참조하도록해야한다. 엔티티의 생성자가 private로 되어있다면 해당 엔티티를 상속한 프록시 엔티티를 만들수가 없다. 상속한 객체의 생성자는 반드시 부모 객체의 생성자 super를 호출해야 하는데, private이면 상속받은 클래스에서 호출할 수 없기 때문이다.
어려운 내용이 있었다면 이를 어떻게 해결하였나요?
x
어떤 자료를 참고하였나요?
The text was updated successfully, but these errors were encountered: