Spring/이론

JPA 기본 - 프록시 객체

레이튼 2023. 6. 28. 15:04

JPA에서 프록시 객체가 중요한 이유는 이후 즉시로딩과 지연로딩의 차이를 공부하는데에 있다.

 

엔티티 객체를 조회할 때는 두가지 메서드가 있다.

EntityManager em;

em.find(): 데이터베이스를 통해서 실제 엔티티 객체를 조회

em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체를 조회

 

프록시 객체 안의 Entity는 처음에 비어있다

프록시 객체는 엔티티 객체를 상속받아서 만들어졌다.

실제 클래스와 겉 모양이 같아 구분이 잘 되지 않으나 실제로 구분해서 쓸 필요는 없다.

 

프록시의 객체는 실제 객체의 참조를 보관한다.

프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.

 

프록시 객체의 초기화 과정이다.

// 프록시 객체 생성 (target은 빈값)
Member member = em.getReference(Member.class, "id1");

// 실제 엔티티 생성 및 프록시 객체를 통한 조회가 이루어지는 단계
member.getName();

프록시의 특징

  • 프록시 객체는 처음 사용할 때 1번만 초기화
  • 프록시 객체를 초기화할 때, 프록시 객체가 실제 엔티티로 바뀌는 것이 아니다. 초기화가 되면 프록시 객체(MemberProxy)를 통해 실제 엔티티(Member)에 접근이 가능하다.
  • 프록시 객체는 원본 엔티티를 상속받는다. 따라서 타입이 완전히 같지 않아 비교시 주의해야 한다. (== 비교 실패, member instance of Member 사용)
  • 영속성 컨텍스트에 찾는 엔티티가 이미 있다면, em.getReference()를 호출해도 실제 엔티티를 반환한다.
Member member = new Member("id1");
em.persist(member);

// 실제 엔티티로 조회해옴.
Member mem1 = em.find(Member.class, "id1");
// 이미 영속성 컨텍스트에 실제 엔티티로 들어있음. -> 프록시 객체가 아닌 실제 엔티티 객체로 반환
Member mem2 = em.getReference(Member.class, "id1");
  • 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 예외가 발생한다.
// 영속성 컨텍스트를 초기화하면 mem1에 대한 정보 날아감. 연결 끊어짐.
// em.detach(); 도 가능
em.clear();

mem1.getName(); // --> 초기화에서 예외 발생
// 이미 연결이 끊어진 관리되지 않고 있는 객체에 접근하려 했기 때문이다.

 

프록시 관련 메소드

프록시 인스턴스의 초기화 여부 확인

em.getPersistenceUnitUtil().isLoaded(member);

 

프록시 클래스 확인 방법

member.getClass().getName();

 

프록시 강제 초기화 (JPA 표준은 강제 초기화가 없어 member.getName()으로 접근하는 방식으로 해줘야 한다)

org.hibernate.Hibernate.initialize(entity);