JPA에서의 프록시
JPA에서 엔티티를 조회할 때, EntityManager.find()
를 이용해서 조회하게 되는데, 만약 해당 엔티티가 영속성 컨텍스트에 존재하지 않으면, 데이터베이스에 조회를 요청하게 된다.
엔티티를 실제로 사용하는 시점까지 데이터베이스 조회를 미루고 싶다면, EntityManager.getReference()
메소드를 사용하면 된다.
해당 메서드는 DB를 조회하지않고, 실제 엔티티 객체를 생성하지도 않는데, 데이터 베이스 접근을 위한 프록시 객체를 반환해준다.
프록시의 사용
- 프록시 클래스는 실제 클래스를 상속 받아서 만들어지므로 진짜 객체인지, 프록시 객체인지 구분하지 않고 사용하면 된다.
- 프록시 객체는 실제 객체의 참조(target)을 보관
- 프록시객체는 실제 객체의 메소드를 호출
프록시 객체의 초기화
Memeber member = em.getReference(Member.class, "id1"); //프록시 객체 생성
member.getName(); //실제 데이터 조회
- 프록시 객체에
member.getName()
호출해서 실제 데이터 조회 - 프록시 객체는 실제 엔티티가 생성되어 있지 않으면, 영속성 컨텍스트에 실제 엔티티 생성을 요청 → 초기화
- 영속성 컨텍스트에서 DB조회해서 실제 엔티티 객체 생성
- 생성된 실제 엔티티의 객체 참조를 Member target 멤버변수에 보환
- 프록시 객체는 실제 엔티티 객체의 getName()을 호출해서 결과 반환
프록시의 특징
- 프록시 객체는 처음 사용할 때 한 번만 초기화
- 초기화시, 프록시 객체가 실제 엔티티로 바뀌는것 X, 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근 가능
- 프록시 객체는 원본 엔티티를 상속받음, 따라서 타입 체크시 == 대신 instance of 사용
- 영속성 컨텍스트에 찾는 엔티티가 이미 존재하면,
em.getReference()
를 호출해도 실제 엔티티를 반환 - 영속성 컨텍스트의 도움을 받을 수 없는 준영속 상태일 때, 프록시를 초기화하면 Exceoption 발생(하이버네이트가 org.hibernate.LazyInitializationException 예외 발생)
프록시 확인
- 프록시 인스턴스의 초기화 여부 확인 :
PersistenceUnitUtil.isLoaded(Object entity)
- 프록시 클래스 확인 :
entity.getClass().getName()
- 프록시 강제 초기화 :
org.hibernate.Hibernate.initialize(entity)
참고
해당 글은 김영한님의 자바 ORM 표준 JPA 프로그래밍을 공부하며 작성한 글입니다.
https://www.inflearn.com/course/ORM-JPA-Basic/dashboard
반응형