프록시
프록시
프록시라는 개념은 소개에서 이야기한듯이 객체 그래프를 통한 편리한 객체 탐색을 도와주는 기술이다.
프록시 객체란?
실제 엔티티 객체 대신에 데이터베이스로 조회를 지연할 수 있는 가짜 객체
프록시 기초
기존에 엔티티 하나를 조회할 때는 EntityManager.find()을 사용해서 조회를 하게 되었다. 먼저 영속성 컨텍스트에서 조회를 해보고, 이후에는 실제로 데이터 베이스에서 조회를 하게 되는데 이렇게 어떠한 엔티티를 사용하든 안하든 일단은 데이터 베이스에 접근해서 조회를 하게 된다.
이런 상황에서 조회를 미루고 싶다면 미루는 방법으로는 EntityManager.reference()라는 함수를 사용해서 미루는 것도 가능하다. 여기에서 이 메소드를 호출하게 되면 데이터 베이스에서 조회하지 않고 실제 엔티티 객체도 가져오지 않고 단순하게 데이터 베이스 접근을 위임한 프록시 객체를 반환한다.
특징
정말 실제 엔티티 대신에 만들어진 객체이기 때문에 실제 클래스를 상속 받아서 만들어졌음으로 실제 객체와 겉 모양이 같다. 그래서 실제 객체와 프록시 객체를 구분하지 않고 사용하면 된다.
그래도 구조적으로 다른 부분은 분명히 존재한다.
기본 객체의 구성이 필드, getter, setter가 존재한다고 예를 들어 보면
프록시 객체의 구성은 원본 객체, getter, setter가 존재한다고 볼 수 있다.
여기서 프록시 객체에서 객체를 사용하는 경우(getter, setter등) 이때 데이터 베이스를 조회하는 과정을 통해서 실제 엔티티 객체를 생성한다. 이렇게 실제 객체를 생성하는 과정을 보고 프록시 초기화라고 한다
프록시 초기화의 과정이다.
프록시 객체를 사용해서 실제 데이터를 요청
만약 실제 객체가 존재하지 않는다면 영속성 컨텍스트에 실제 엔티티 생성을 요청을 하고 이 과정이 초기화
영속성 컨텍스트는 요청을 받고 객체가 자신에게 없다면 DB를 조회해서 실제 객체 생성
프록시는 실제 객체 의 참조를 저장하게 되고
프록시 객체는 실제 객체의 사용함수를 호출해서 결과를 반환해준다.
프록시의 특징을 정리해보면
프록시 객체는 처음 사용할 때 한 번만 초기화된다.
프록시 객체를 초기화한다(=실제 객체를 생성)고 해서 프록시 객체가 실제로 바뀌는 것이 아니라 단순하게 실제 객체로 접근할 수 있게 되는 것 뿐
프록시 객체는 실제 객체를 상속받은 객체이기 때문에 타입 체크 시 주의
영속성 컨텍스트에 찾는 엔티티가 이미 있다면 데이터 베이스를 조회할 필요가 없기 때문에 getReference()를 해도 프록시가 아니라 실제 객체를 리턴
프록시 객체의 초기화는 영속성 컨텍스트에 의존적이기 때문에 만약에 영속성 컨텍스트과 관련없는 준영속 상태의 객체를 초기화하거나 하면 당연히 에러가 나온다
JPA의 기본 설정 값으로는 지연 로딩(프록시)에 대한 내용은 JPA 구현체에 맡겨두었다. 따라서 준영속 상태의 엔티티를 초기화할 때 어떤 일이 발생할지는 따로 예외처리를 해주지 않는 이상은 그냥 지연 로딩에 대한 예외가 발생한다..!
프록시의 식별
엔티티를 프록시로 조회할 때 식별자의 값을 파라미터로 전달하게 되는데, 프록시 객체는 이 식별자 값을 보관하게 된다.
프록시 객체는 식별자 값을 가지고 있기 때문에 식별자 값을 조회하는 team.getId()를 호출해도 프록시를 초기화하지 않는다.
여기서 엔티티의 접근 방식을 필드(@Access(AccessType.FIELD))로 설정하게 되면 JPA는 getId() 메소드가 id만 조회하는 메소드인지 다른 이상한 메소드인지 모르게 프록시 객체를 초기화한다.
연관 관계를 설정할 때는 식별자 값만 사용하기 때문에 프록시를 사용하게되면 db 접근 횟수를 줄일 수 있다
연관관계 설정시 엔티티 접근 방식을 필드로 설정해도 프록시를 초기화하지 않음
프록시 확인
PersistenceUnitUtil.isLoaded(Object entity)메소드를 사용해서 프록시 인스턴스의 초기화 여부를 확인할 수 있다.
아직 초기화 안되었다면 false, 초기화 되었거나 프록시 인스턴스가 아니면 true를 리턴해줌
Last updated
Was this helpful?