스프링

프록시

148june 2025. 4. 18. 16:47

🧩 프록시(Proxy)란?

JPA에서 em.getReference()를 호출하면 실제 엔티티 객체가 아닌 프록시 객체를 반환해. 이 프록시는 지연 로딩(Lazy Loading) 을 위한 가짜 객체야.


🔁 프록시의 목적

  • DB 접근을 지연시키기 위해 사용돼.
  • 엔티티의 실제 데이터를 당장 불러오지 않고, 필요할 때 DB에서 조회하게 만들어.

✅ 프록시 작동 방식

Tutor proxyTutor = em.getReference(Tutor.class, tutor.getId());
  • 이 시점에서는 DB에 쿼리를 날리지 않음
  • 대신 Tutor를 상속받은 프록시 객체가 생성됨
  • proxyTutor.getName() 같이 프록시의 필드에 접근하면 그 시점에 DB 조회 발생

✅ 프록시 특징 정리

특징 설명

em.find() vs em.getReference() find()는 즉시 조회, getReference()는 프록시 반환 (지연 로딩)
프록시 클래스 Hibernate가 내부적으로 만든 CGLIB 클래스ex. com.example.Tutor$HibernateProxy
DB 조회 시점 속성에 실제로 접근할 때 조회 발생 (getName() 등)
== 비교 프록시와 실제 객체는 다름, == 비교 실패
instanceof 성공 (proxy instanceof Tutor == true)
초기화 여부 최초 1회만 DB 조회됨
영속성 컨텍스트 준영속 상태(detach) 에서 접근하면 LazyInitializationException 발생

✅ 예시 흐름

// 프록시 반환
Tutor proxyTutor = em.getReference(Tutor.class, 1L);

// 실제 데이터 조회는 여기서!
proxyTutor.getName(); // 이때 DB 조회
// ❗준영속 상태에서는 에러 발생
em.detach(proxyTutor);
proxyTutor.getName(); // ❌ LazyInitializationException

⚠️ 프록시 사용 시 주의사항

  • 컨트롤러 등에서 프록시 객체를 그대로 JSON 직렬화하면 에러 발생
    → 예: Could not write JSON: failed to lazily initialize a collection
  • 테스트 코드에서 프록시를 사용할 땐 em.clear() 후 접근에 주의해야 함
  • 프록시는 영속성 컨텍스트 안에서만 의미 있음

🧠 요약 한 줄 정리

프록시는 실제 엔티티 대신 "껍데기 객체" 를 반환하고, 실제 데이터는 필요할 때만 가져오는 지연 로딩 도우미다.