아래의 포스트를 읽기전에 프록시 객체에 대한 개념이 부족하다면
About Proxy를 먼저 읽고 아래의 포스트를 읽는 것을 추천한다.
Member member = em.getReference(Member.class, "id1"); // 프록시 객체 반환
member.getName(); // 프록시가 이 때 초기화된다.
프록시가 초기화되면 원본객체로 바뀌는 것이 아니라 프록시 객체의 타겟이 원본객체로 설정되는 것이다. 따라서 위의 코드에서 member.getName()
을 하면 Member 원본객체의 메소드가 호출되는 것이 아니고, Member 프록시 객체의 메소드가 호출된 뒤 target에 의해 Member 원본 객체의 메소드가 호출되는 것이다.
Member member1 = new Member();
member1.setUsername("member1");
em.persist(member1);
Member member2 = new Member();
member2.setUsername("member2");
em.persist(member2);
em.flush();
em.clear();
Member m1 = em.find(Member.class, member1.getId());
Member m2 = em.find(Member.class, member2.getId());
System.out.println("m1 == m2: " + (m1.getClass() == m2.getClass())); // true
Member m1 = em.find(Member.class, member1.getId());
Member m2 = em.getReference(Member.class, member2.getId());
System.out.println("m1 == m2: " + (m1.getClass() == m2.getClass())); // false
프록시 객체는 처음 사용할 때 한번만 초기화 된다.
프록시 객체를 초기화할 때, 프록시 객체가 실제 엔티티로 바뀌는 것이 아니다.
-> 초기화되면 프록시 객체를 통해서 실제 엔티티에 접근하는 것이다.
프록시 객체는 원본 엔티티를 상속받는다. 따라서 타입 체크시 주의해야한다.
-> 원본 엔티티와 == 비교를 하면 실패한다. 따라서 instance of
를 사용해야 한다.
Member m1 = em.find(Member.class, member1.getId());
Member m2 = em.getReference(Member.class, member1.getId());
System.out.println(m1.getClass()); // class hellojpa.Member
System.out.println(m2.getClass()); // class hellojpa.Member
Member m2 = em.getReference(Member.class, member1.getId());
Member m1 = em.find(Member.class, member1.getId());
System.out.println(m1.getClass()); // class hellojpa.Member$HibernateProxy$l3UMcB5d
System.out.println(m2.getClass()); // class hellojpa.Member$HibernateProxy$l3UMcB5d
em.getReference()
를 호출해도 실제 엔티티를 반환한다.Member member1 = new Member();
member1.setUsername("member1");
em.persist(member1);
em.flush();
em.clear();
Member m2 = em.getReference(Member.class, member1.getId());
em.detach(m2); // 준영속 상태로 만들기
System.out.println(m2.getUsername()); // 예외 발생!
프록시 인스턴스의 초기화 여부 확인
Member m2 = em.getReference(Member.class, member1.getId());
System.out.println(emf.getPersistenceUnitUtil().isLoaded(m2)); // false
m2.getUsername();
System.out.println(emf.getPersistenceUnitUtil().isLoaded(m2)); // true
프록시 객체의 클래스를 확인할 수 있다.
프록시 객체를 강제로 초기화시킨다.
Member m2 = em.getReference(Member.class, member1.getId());
Hibernate.initialize(m2);
System.out.println(emf.getPersistenceUnitUtil().isLoaded(m2)); // true