개요
이전 글에서 Hibernate의 AnnotationBinder에서 어떻게 연관 관게를 처리하는지 알아보았다. 그때 흥미로운 점이 바로 어노테이션 메타 데이터를 아래와 같은 형태로 검증한다는 것이었다.
if (property.isAnnotationPresent(OneToOne.class))
이 이 property는 어떤식으로 설계되어 있는지 궁금하여 분석해보았는데, 같은 글에 다루기에는 양이 방대할 것 같아서 별도의 내용으로 글을 작성하기로 하였다.
(JPA) Hibernate는 내부적으로 어떻게 연관 관계 어노테이션을 처리할까? (feat: AnnotationBinder, Hibernate 5
개요이전 글에서 Lazy와 Eager 중 Lazy를 사용해 성능을 튜닝해야 한다는 이야기를 했었다. 이번 포스팅에서는 JPA가 내부적으로 Lazy와 Eager 로딩을 어떻게 구분하는지, 그리고 이를 판단하는 주체가
wise-dev-seop.tistory.com
내용
Hibernate는 엔티티 클래스의 메타데이터(예: 속성, 어노테이션 등)를 처리하기 위해 자체적인 리플렉션 추상화를 사용한다. 이를 통해 Hibernate는 다양한 리플렉션 메커니즘과 환경에서 일관되게 동작하는 것이다. 주요 구성요소는 아래와 같다.
- XProperty: 클래스의 속성을 나타내며, 이는 필드나 getter 메서드임.
- XMember: 클래스의 멤버를 일반적으로 나타내며, 속성이나 메서드를 포함함.
- XAnnotatedElement: 어노테이션이 적용될 수 있는 요소(클래스, 필드, 메서드 등)를 나타냄.
또한 위 데이터 클래스들은 아래와 같이 계층 구조를 가진다.
- JavaXAnnotatedElement (추상 클래스)
- JavaXMember (추상 클래스)
- JavaXProperty (구체 클래스) -> 이것이 property.isAnnotationPresent(OneToOne.class) 에서 property의 자료형. 흥미로운 점은 isAnnotationPresent는 JavaXAnnotatedElement 레벨에서부터 정의되어 내려온다.
- JavaXMember (추상 클래스)
그럼 이제 이 계층 구조를 가장 부모단에서부터 살펴보자.
JavaXAnnotatedElement 클래스 (Grand Parent)
package org.hibernate.annotations.common.reflection.java;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import org.hibernate.annotations.common.reflection.AnnotationReader;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
abstract class JavaXAnnotatedElement implements XAnnotatedElement {
private final JavaReflectionManager factory;
private final AnnotatedElement annotatedElement;
public JavaXAnnotatedElement(AnnotatedElement annotatedElement, JavaReflectionManager factory) {
this.factory = factory;
this.annotatedElement = annotatedElement;
}
protected JavaReflectionManager getFactory() {
return this.factory;
}
private AnnotationReader getAnnotationReader() {
return this.factory.buildAnnotationReader(this.annotatedElement);
}
@Override
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
return this.getAnnotationReader().getAnnotation(annotationType);
}
@Override
public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
return this.getAnnotationReader().isAnnotationPresent(annotationType);
}
@Override
public Annotation[] getAnnotations() {
return this.getAnnotationReader().getAnnotations();
}
AnnotatedElement toAnnotatedElement() {
return this.annotatedElement;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof JavaXAnnotatedElement)) {
return false;
} else {
JavaXAnnotatedElement other = (JavaXAnnotatedElement) obj;
return this.annotatedElement.equals(other.toAnnotatedElement());
}
}
@Override
public int hashCode() {
return this.annotatedElement.hashCode();
}
@Override
public String toString() {
return this.annotatedElement.toString();
}
}
JavaXAnnotatedElement는 어노테이션이 적용될 수 있는 요소(클래스, 필드, 메서드 등)에 대한 공통 기능을 제공하는 추상 클래스이다. 이는 어노테이션의 존재 여부를 확인하거나 특정 어노테이션을 가져오는 작업을 처리한다.
JavaXAnnotatedElement 클래스의 주요 기능
어노테이션 처리
getAnnotation, isAnnotationPresent, getAnnotations 메서드를 통해 어노테이션의 존재 여부를 확인하거나 특정 어노테이션을 가져온다.
@Override
public <T extends Annotation> boolean isAnnotationPresent(Class<T> annotationType) {
return this.getAnnotationReader().isAnnotationPresent(annotationType);
}
어노테이션 리더 사용
AnnotationReader를 사용하여 실제 어노테이션 데이터를 읽어온다.
private AnnotationReader getAnnotationReader() {
return this.factory.buildAnnotationReader(this.annotatedElement);
}
객체 비교 및 해시코드
equals 및 hashCode 메서드를 오버라이드하여 동일한 AnnotatedElement를 가진 객체는 동일하게 취급된다.
JavaXMember 클래스 (Parent)
package org.hibernate.annotations.common.reflection.java;
import java.lang.reflect.Member;
import java.lang.reflect.Type;
import org.hibernate.annotations.common.reflection.XMember;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.java.generics.TypeEnvironment;
public abstract class JavaXMember extends JavaXAnnotatedElement implements XMember {
private final Type type;
private final TypeEnvironment env;
private final JavaXType xType;
protected JavaXMember(Member member, Type type, TypeEnvironment env, JavaReflectionManager factory, JavaXType xType) {
super((AnnotatedElement) member, factory);
this.type = type;
this.env = env;
this.xType = xType;
}
@Override
public abstract String getName();
@Override
public Type getJavaType() {
return this.env.bind(this.type);
}
// 기타 메서드...
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return getAnnotationReader().isAnnotationPresent(annotationType);
}
}
JavaXMember는 클래스의 멤버(필드 또는 메서드)에 대한 메타데이터를 관리하는 추상 클래스이다. 이는 JavaXAnnotatedElement를 상속받아 어노테이션 관련 기능을 포함하며, 멤버의 이름, 타입, 접근 권한 등을 제공하는 기능을 추가로 제공한다.