프록시

slee2·2022년 3월 7일
0
post-thumbnail

프록시 기초

  • em.find() vs em.getReference()
  • em.find(): 데이터베이스를 통해서 실제 엔티티 객체 조회
  • em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체 조회

em.find()의 경우 메서드가 실행되는 시점에 바로 DB에 쿼리를 날린다.
그런데 em.getReference()의 경우 실제 값이 사용되기 전까지 DB에 쿼리를 날리지 않는다.

em.getReference()의 클래스를 조회하면 이렇게 나온다.
hellojpa.Member$HibernateProxy$odcVHpjy
이는 하이버네이트가 프록시라고 하는 가짜 엔티티를 주는 것이다.

프록시 특징

  • 실제 클래스를 상속 받아서 만들어짐
  • 실제 클래스와 겉 모양이 같다.
  • 사용하는 입장에서는 진짜 객체인지 프록시 객체인지 구분하지 않고 사용하면 됨.(이론상)

  • 프록시 객체는 실제 객체의 참조(target)를 보관
  • 프록시 객체를 호출하면 프록시 객체는 실제 객체의 메서드 호출

프록시 객체 초기화

Member member = em.getReference(Member.class, “id1”); 
member.getName();
  • 프록시 객체는 처음 사용할 때 한 번만 초기화
  • 프록시 객체를 초기화 할 때, 프록시 객체가 실제 엔티티로 바뀌는 것은 아님, 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능
  • 프록시 객체는 원본 엔티티를 상속받는다. 따라서 타입 체크시 주의해야한다.(== 비교 대신, instance of를 사용해야한다.)
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있으면 em.getReference()를 호출해도 실제 엔티티 반환
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 문제 발생(하이버네이트는 LazyInitializationException 예외 발생)

이런 경우는 많이 없긴한데, JPA에서는 프록시와 Member 객체를 같게 하는 것을 보장해줘야한다.
그러므로 처음에 em.find() -> em.getReference()를 한다면, 두 객체 모두 Member로 나오고, 순서가 반대면 둘다 프록시가 나옴.

프록시 확인

  • 프록시 인스턴스의 초기화 여부 확인
    PersistenceUnitUtil.isLoaded(Object entity)
  • 프록시 클래스 확인 방법
    entity.getClass().getName() 출력
  • 프록시 강제 초기화
    org.hibernate.Hibernate.initialize(entity);
  • 참고: JPA 표준은 강제 초기화 없음
    강제 호출: member.getName()

0개의 댓글