JPA에서 프록시 객체가 중요한 이유는 이후 즉시로딩과 지연로딩의 차이를 공부하는데에 있다.
엔티티 객체를 조회할 때는 두가지 메서드가 있다.
EntityManager em;
em.find(): 데이터베이스를 통해서 실제 엔티티 객체를 조회
em.getReference(): 데이터베이스 조회를 미루는 가짜(프록시) 엔티티 객체를 조회
프록시 객체는 엔티티 객체를 상속받아서 만들어졌다.
실제 클래스와 겉 모양이 같아 구분이 잘 되지 않으나 실제로 구분해서 쓸 필요는 없다.
프록시의 객체는 실제 객체의 참조를 보관한다.
프록시 객체를 호출하면 프록시 객체는 실제 객체의 메소드를 호출한다.
프록시 객체의 초기화 과정이다.
// 프록시 객체 생성 (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);
'Spring > 이론' 카테고리의 다른 글
JPA - 영속성 전이, 고아 객체 (0) | 2023.06.29 |
---|---|
JPA 기본 - 지연 로딩 즉시 로딩 (0) | 2023.06.28 |
웹 애플리케이션 이해 (0) | 2022.07.14 |
빈 스코프(Bean Scope)란? (0) | 2022.07.04 |
컴포넌트 스캔 (0) | 2022.07.04 |