📌 프록시(Proxy)란?
프록시는 대리 객체라고도 불린다. 실제 객체 대신 가짜 객체를 먼저 생성해서 필요할 때만 실제 객체에 접근하도록 도와주는 디자인 패턴이다.
JPA에서는 데이터베이스 조회 성능 최적화를 위해서 프록시 객체를 사용한다.
📌 JPA에서의 프록시 동작 방식
Member member = em.getReference(Member.class, memberId);
이렇게 호출하면 JPA는 바로 데이터베이스에서 값을 조회하지 않고 프록시 객체만 반환한다.
📌 프록시를 사용해야 하는 이유
✔️ 지연 로딩(Lazy Loading)
- 엔티티의 연관된 데이터를 바로 조회하지 않고, 실제 접근할 때만 DB에 조회 쿼리를 실행한다.
- 즉, 성능 최적화와 메모리 절약 효과가 있다.
✔️ 최소한의 DB 조회
엔티티의 ID 값만 필요하다면 굳이 모든 필드를 조회하지 않고 프록시 객체만 반환한다.
📌 프록시의 내부 구조
- 식별자(ID)만 가지고 있으며, 나머지 필드는 가짜로 채워져 있다.
- 만약, 엔티티의 다른 필드 정보가 더 필요하다면 DB에서 데이터를 조회해서 실제 엔티티 객체를 초기화한다.
- Hibernate는 이를 초기화 트리거 (Lazy Initialozation)라고 한다.
Member member = em.getReference(Member.class, memberId);
System.out.println(member.getClass());
// 식별자만 조회할 때는 초기화 X
System.out.println(member.getId()); // DB 조회 안함
// 다른 필드에 접근하면 DB 조회 발생 (프록시 초기화)
System.out.println(member.getUsername()); // DB 조회 발생

프록시 초기화 과정
- em.getReference() 호출 → 프록시 객체 반환
- 엔티티의 식별자(ID) 외의 필드 접근 시 → DB 조회 발생 (초기화)
- 실제 엔티티의 데이터가 프록시 객체의 target 필드에 저장
- 프록시 객체는 여전히 프록시지만, 내부적으로 실제 엔티티의 데이터를 가진다.
💡 중요한 점
- 초기화 전에는 프록시 객체가 식별자만 가지고 있다.
- 초기화 후에는 프록시 객체가 실제 엔티티 데이터를 target 필드에 보관하지만
타입은 프록시 객체의 타입 그대로 유지된다.
🚨 주의사항
- 프록시 객체는 영속성 컨텍스트가 살아있을 때만 초기화가 가능하다.
- 영속성 컨텍스트가 종료된 상태에서 프록시 객체에 접근하면 LazyInitializationException이 발생한다.
- 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 주의해야함 (== 비
교 실패, 대신 instance of 사용)